Friday.NET it's a general-purpose framework for solving a variety of applied problems
Contains the following assemblies
Lots of extension methods, Routing, and auxiliary classes useful almost in every project.
- NET Core compatible
- Xamarin compatible
- Unity3d compatible
- Third Party Reference free
Useful in network applications with custom protocol messages, when they must be routed to specific processors
Sample classes
class BaseMessage
{
}
class DerivedMessage : BaseMessage
{
}
class Processor: IMessageHandler<DerivedMessage>
{
public void HandleMessage(DerivedMessage message)
{
//Some handling logic
}
}
Consider Abstract message receiver (Can be Websocket, byte stream e.t.c)
class Transport
{
private readonly RoutingProvider routingProvider;
Transport()
{
routingProvider = new RoutingProvider();
var routeRule= new RouteRule(new Processor(), RouteOptions.UseInterfaceMessageHandler());
routingProvider.RegisterRoute(routeRule);
}
private BaseMessage DeserializeMessage(string textMessage)
{
return new DerivedMessage();
}
public void OnMessage(string textMessage)
{
BaseMessage baseMessage= DeserializeMessage(textMessage);
routingProvider.RouteObject(baseMessage); //Will trigger HandleMessage in our Processor
}
}
You can also route methods
interface IConnectionEstablished
{
void ProcessConnectionEstablished();
}
//RouteCall will call corresponding method in each registered route that implement IConnectionEstablished
routingProvider.RouteCall<IConnectionEstablished>(processor => processor.ProcessConnectionEstablished());
class Processor : IMessageHandlerAsync<DerivedMessage>
{
public async Task HandleMessage(DerivedMessage message)
{
await Task.Delay(TimeSpan.FromSeconds(10));
//process message
}
}
For async routing you can use Async call
await routingProvider.RouteObjectAsync(baseMessage);
Or use regular call
routingProvider.RouteObject(baseMessage);
try
{
routingProvider.RouteObject(baseMessage);
}
catch(Exception e)
{
//...
}
Attribute method protection also could be used, Friday.Base include AuthRequiredAttribute
class AuthRequestDto
{
public string UserName{get;set;}
}
internal class AuthRequiredApiProcessor : IMessageHandler<DerivedMessage>, IContextMessageHandler<AuthRequestDto>
{
[AuthRequired]
public void HandleMessage(DerivedMessage message)
{
//message processing AFTER client authorized
}
public void HandleMessage(IRoutingContext context, AuthRequestDto message)
{
context.Principal = new BasicUserNamePrincipal(message.UserName);
}
}
Register processor with attribute handler
routingProvider = new RoutingProvider();
var routeRule= new RouteRule(new AuthRequiredApiProcessor(), RouteOptions.UseInterfaceMessageHandler());
routingProvider.RegisterAttributeHandler(new AuthRequiredAttributeHandler());
routingProvider.RegisterRoute(routeRule);
Attempt to route message before authorization:
routingProvider.RouteObject(new DerivedMessage()); //Will generate NotAuthorizedException
For example you develop a public API library with many events
class BaseMessage
{
}
class SomeMessage : BaseMessage
{
}
class SomeOtherMessage : BaseMessage
{
}
class MyApplicationApi
{
public event EventHandler<SomeMessage> OnSomeMessage;
public event EventHandler<SomeOtherMessage> OnSomeOtherMessage;
}
Calling of each event can be painful
private void OnMessage(BaseMessage message)
{
if(message is out SomeMessage sm)
OnSomeMessage?.Invoke(sm);
//and for each message type same code
}
Offcourse you can generate T4 template for that kind of stuff but...
How about that?
private void OnMessage(BaseMessage message)
{
EventUtils.InvokeAppropriateEvent(this,message); //will find corresponding EventHandler in 'this', and call it.
}
enum Numbers
{
One,
Two,
Three
}
public void Test()
{
var testEnum = Numbers.One;
testEnum = testEnum.Next(); //testEnum now contain Two
testEnum = testEnum.RandomValue(seed:222); //testEnum now contain Three
}
var list = new List<string> {"one", "two", "three", "four","five"};
Take random element
list.TakeRandom();
Separate list to many chunks
void ChunkifyDemo()
{
var chunks=list.TakeChunks(2);
//chunks now contain 2 elements
//"one","two"
//"three", "four","five"
}
Shuffle (random order)
list = list.Shuffle();
Swap
list.Swap("one", "two");
//output two one three four
Or by index
list.Swap(0, 1);
//output two one three four
Standart separator
string debuggerOutput= list.ToPrettyString();
/*
one
two
three
four
five
*/
Any separator
string debuggerOutput= list.ToPrettyString(",");
/*
one,two,three,four,five
*/
Dictionary
var dictionary = new Dictionary<int,string>()
{
{0,"zero" },
{1,"one" },
}
var debuggerOutput=dictionary.ToPrettyString();
/*
0=zero
1=one
*/
Automapper is super cool but sometimes it's too complicated for simple mapping
So meet simpliest ever mapping
class Entity
{
public string UserName{get;}
public float Field;
}
class SomeMessageDto
{
public string UserName;
public float Field;
}
[TestMethod]
void MappingShouldSuccess()
{
var entity = new Entity();
var dto=entity.MapPropertiesWithFieldsTo<SomeMessageDto>();
Assert.IsTrue(entity.UserName==dto.UserName);
Assert.IsTrue(entity.Field==dto.Field);
}
Or
SomeDto dto=new SomeDto();
entity.MapPropertiesWithFieldsTo(dto);
Or even
SomeDto dto=new SomeDto();
dto.MapPropertiesWithFieldsFrom(entity);
void StringExtensionsDemo()
{
string s="Hello KittY, Avilo super mech terran";
s.Contains("Avilo"); //true
s.ContainsNoCase("kitty"); //true
s.IsValidEmail(); //false
}
struct ExampleStruct
{
public int A;
public string B;
}
void Demo()
{
var exampleStruct= new ExampleStruct();
byte[] array=exampleStruct.ToByteArray(); //ready for network send
var restoredStruct=array.ToStructure<ExampleStruct>(); //restore it ;)
}
Exception e= new Exception();
e.GetDeepestInnerException();
var rc = new ReferenceCounter();
rc.OnNoReferencesLeft += ()=> Console.WriteLine("No References left, object can be disposed");
rc.Acquire();
rc.Release();
FridayRandom.SetSeed(seed:1234);
FridayRandom.IsRandomChanceOccured(chanceInPercent: 50);
FridayRandom.GetNext(0,100);
FridayRandom.GetNextIncludingMax(0,100);
void Foo()
{
Console.WriteLine(Uptime.FullUptime); //print App uptime
FridayDebugger.SafeBreak(); // Break only if debugger attached
}