diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/404.html b/404.html new file mode 100644 index 00000000..2d9386ee --- /dev/null +++ b/404.html @@ -0,0 +1,424 @@ + + + +
+ + + + + + + + + + + + + +A toolkit for .NET projects.
+ +This project is proudly maintained by @guibranco
+Source code available at: GitHub
+ +Build status | +Last commit | +Tests | +
---|---|---|
+ | + | + |
Coverage | +Code Smells | +LoC | +
---|---|---|
+ | + | + |
The Crispy Waffle project is divided into some packages:
+Package | +Description | +
---|---|
CrispyWaffle | +The core package, with main features. | +
Configuration | +Configuration abstractions. | +
ElasticSearch | +The ElasticSearch extension package. Implements the Elastic Search client and log features. |
+
ELMAH | +The ELMAH exception handler. Redirects the exceptions messages (from LogConsumer.Handle method) to ELMAH. |
+
Log4Net | +The Log4Net log provider. Redirects the log output to Log4Net. |
+
RabbitMQ | +The RabbitMQ extension package. Implements the RabbitMQ message broker client and log features. |
+
Redis | +The Redis extension package. Implements the Redis cache, log and telemetry features. |
+
Utils | +The utility extension package. Implements the utilities classes (communications - FTP client, SMTP mailer). |
+
Download the latest zip file from the Release page.
+CrispyWaffle
+Install-Package CrispyWaffle
+
+Configuration
+Install-Package CrispyWaffle.Configuration
+
+ElasticSearch
+Install-Package CrispyWaffle.ElasticSearch
+
+ELMAH
+Install-Package CrispyWaffle.Elmah
+
+Log4Net
+Install-Package CrispyWaffle.Log4Net
+
+RabbitMQ
+Install-Package CrispyWaffle.RabbitMQ
+
+Redis
+Install-Package CrispyWaffle.Redis
+
+Utils
+Install-Package CrispyWaffle.Utils
+
+
+
+
+
+
+
+ MIT License
+Copyright (c) 2019-2023 Guilherme Branco Stracini
+Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.
+ + + + + + +The Crispy Waffle has the following features:
+Most methods are tested and have usage examples in test project source code.
+ + + + + + +Cache data is easy with Crispy Waffle, there are available two repositories for cache:
+There is also a helper class, CacheManager that make cache usage easy.
+The following example uses the RedisCacheRepository and the CacheManager helper class:
+Process #1 (write data to cache):
+ServiceLocator.Register<ICacheRepository, RedisCacheRepository>(LifeStyle.SINGLETON);
+CacheManager.AddRepository<ICacheRepository>();
+
+CacheManager.Set("some string text", "MyKey");
+
+Process #2 (read data from cache - Redis):
+ServiceLocator.Register<ICacheRepository, RedisCacheRepository>(LifeStyle.SINGLETON);
+CacheManager.AddRepository<ICacheRepository>();
+
+var cachedValueFromRedis = CacheManager.Get<string>("MyKey"); //some string text
+
+Using multiple cache repositories:
+ServiceLocator.Register<ICacheRepository, MemoryCacheRepository>(LifeStyle.SINGLETON);
+ServiceLocator.Register<RedisCacheRepository>(LifeStyle.SINGLETON);
+
+CacheManager.AddRepository<ICacheRepository>(); //or directly: CacheManager.AddRepository<MemoryCacheRepository>();
+CacheManager.AddRepository<RedisCacheRepository>(); //RedisCacheRepository
+
+var cachedValue = CacheManager.Get<string>("MyKey"); //first will lookup in MemoryCacheRepository then RedisCacheRepository
+
+var cachedValueFromSpecificRepository = CachemManager.GetFrom<RedisCacheRepository, string>("MyKey"); //will get the value only from RedisCacheRepository.
+
+
+
+
+
+
+
+ Events are a way to execute one or more actions based on a class (the event itself).
+Events are defined as a simple class, inherited from IEvent
interface.
Each event can be handled by one, two or infinite number of event handlers.
+Event handler class inherit from IEventHandler<TEvent>
interface and must implement the Handle(TEvent evt)
method.
+The TEvent
generic type is the type of IEvent
that will be handled.
For example, the HelloWorldEvent
class, defined below is a simple class without methods, properties or fields and is used to trigger HelloWorldEventHandler
:
Event class:
+public class HelloWorldEvent : IEvent {}
+
+Event handler class:
+public class HelloWorldEventHandler : IEventHandler<HelloWorldEvent>
+{
+ public Handle(HelloWorldEvent evt)
+ {
+ Console.WriteLine("Hello World triggered!");
+ }
+}
+
+To trigger the event handler just call the EventsConsumer.Raise
method from any part of your code:
EventsConsumer.Raise(new HelloWorldEvent());
+//do other stuff...
+
+Each event handler can handle many kinds of events, just need to implement each interface and each method Handle
.
Event handling is currently done synchronously. There are plans to do async, issue #XX.
+A more complex example using Events
& EventsHandlers
.
+In this example, there are two event handlers and the event class has some properties:
//The event class.
+public class SomeEvent : IEvent
+{
+ public SomeEvent(string data)
+ {
+ Id = Guid.NewGuid();
+ Date = DateTime.Now;
+ Data = data;
+ }
+
+ public Guid Id { get; }
+
+ public string Data { get; }
+
+ public DateTime Date { get; }
+}
+
+//The event handler class. Each event can be handled by N event handlers.
+public class SomeEventHandler : IEventHandler<SomeEvent>
+{
+ //constructor of the class, with dependencies...
+ //dependencies are resolved by ServiceLocator.
+
+ public void Handle(SomeEvent args)
+ {
+ LogConsumer.Warning("Event 'SomeEvent' handled by 'SomeEventHandler'. Event Id: {0}", args.Id);
+ //do any other processing stuff...
+ }
+}
+
+public class AnotherSomeEventHandler : IEventHandler<SomeEvent>
+{
+ //constructor of the class, with dependencies...
+ //dependencies are resolved by ServiceLocator.
+
+ public void Handle(SomeEvent args)
+ {
+ LogConsumer.Warning("Event 'SomeEvent' handled by 'AnotherSomeEventHandler'. Event Id: {0}", args.Id);
+
+ //someOtherDependency.DoSomeStuffWithEvent(args.Id, args.Data);
+ //do any other processing stuff...
+ }
+}
+
+// Program entry point
+public static class Program
+{
+ public static void Main(string[] args)
+ {
+ //Initialize the dependencies with ServiceLocator.
+ //Initialize log providers/adapters
+ //...
+
+ var evt = new SomeEvent ("Some text passed to all event handlers");
+ EventsConsumer.Raise(evt);
+ }
+}
+
+
+
+
+
+
+
+ The Crispy Waffle provides some logs providers/adapters for loggin purproses.
+Default providers:
+EventLogAdapter
.Default adapters:
+A simple console application
with simple (colored console output) logging example:
static void Main(string[] args)
+{
+ //Registering the standard console log adapter to be used by console log provider.
+ ServiceLocator.Register<IConsoleLogAdapter, StandardConsoleLogAdapter>(LifeStyle.SINGLETON);
+
+ //Registering the null exception handler for the method LogConsumer.Handle, this means that no action will be executed for exceptions handled by LogConsumer.
+ ServiceLocator.Register<IExceptionHandler, NullExceptionHandler>(LifeStyle.SINGLETON);
+
+ //Adding console provider to LogConsumer, the log provider will use the registered IConsoleLogAdapter.
+ LogConsumer.AddProvider<ConsoleLogProvider>();
+
+ LogConsumer.Info("Hello world Crispy Waffle");
+
+ LogConsumer.Debug("Current time: {0:hh:mm:ss}", DateTime.Now);
+
+ LogConsumer.Warning("Press any key to close the program!");
+
+ Console.ReadKey();
+}
+
+
+
+
+
+
+
+ The Crispy Waffle provides a set of helpers to send/receive messaging over RabbitMq broker.
+Send message to a RabbitMq exchage:
+
+[ExchangeName("rabbitmq-exchange-name")]
+[Serializer(SerializerFormat.JSON)]
+public class SampleItemDto
+{
+ public Guid Id { get; set; }
+
+ public string Text { get; set; }
+
+ public DateTime Date { get; set; }
+}
+
+static void Main(string[] args)
+{
+ //Registering the RabbitMq connector as singleton lifecycle.
+ ServiceLocator.Register<RabbitMQConnector>(LifeStyle.SINGLETON);
+
+ var data = new SampleItemDto
+ {
+ Id = Guid.NewGuid(),
+ Text = "some random text",
+ Date = DateTime.Now
+ };
+
+ //Gets the wrapper
+ var wrapper = ServiceLocator.Resolve<RabbitMQWrapper>();
+
+ //Send to exchange (the exchange name is set via attributes in the SampleItemDto declaration)
+ wrapper.SendToExchange(data);
+
+ Console.ReadKey();
+}
+
+Send message to a RabbitMq queue:
+
+[QueueName("rabbitmq-queue-name")]
+[Serializer(SerializerFormat.JSON)]
+public class SampleItemDto
+{
+ public Guid Id { get; set; }
+
+ public string Text { get; set; }
+
+ public DateTime Date { get; set; }
+}
+
+static void Main(string[] args)
+{
+ //Registering the RabbitMq connector as singleton lifecycle.
+ ServiceLocator.Register<RabbitMQConnector>(LifeStyle.SINGLETON);
+
+ var data = new SampleItemDto
+ {
+ Id = Guid.NewGuid(),
+ Text = "some random text",
+ Date = DateTime.Now
+ };
+
+ //Gets the wrapper
+ var wrapper = ServiceLocator.Resolve<RabbitMQWrapper>();
+
+ //Send to queue (the queue name is set via attributes in the SampleItemDto declaration)
+ wrapper.SendToQueue(data);
+
+ Console.ReadKey();
+}
+
+
+
+
+
+
+
+ Scheduler jobs allows schedule the execution of some method/action using CRON expressions
.
Currently supports the following formats:
+*
: translates to * * * * *
(every minute
, every day
).10
: translates to 10 * * * *
(every 10th minute
of every hour
on every day
).10 1 * * 0
: runs every 1:10 am
of every Sunday
*/10
: runs at 0, 10, 20, 30, 40 and 50
minute of every hour
on every day
.*/20 * 10,20,30 * *
: runs at 0, 20 and 40
minute of every hour
only in days 10, 20 or 30
of each month, independently of the week day. Check the Wikipedia's CRON
page for more examples and details.
Using cron
expression to schedule tasks/jobs inside a program.
public static class Program
+{
+ public static void Main(string[] args)
+ {
+ var exampleObj = new SomeClass();
+ exampleObj.Counter = 10;
+
+ var jobManager = new JobManager();
+ jobManager.AddJob(new JobRunner("* * * * *", () => { exampleObj.Counter++; }));
+ jobManager.Start();
+
+ Thread.Sleep(120 * 1000); //waits 2 minutes
+
+ jobManager.Stop(); //stops the manager, so no more execution runs.
+
+ if(exampleObj.Counter == 12)
+ {
+ LogConsumer.Warning("Example job runned for 2 times!");
+ }
+
+ }
+
+ internal class SomeClass
+ {
+ public int Counter { get; set; }
+ }
+
+}
+
+
+
+
+
+
+
+
+ The service locator class is a helper class that acts like a IoC container. +You can register instances as singleton/transient scope. Register dependencies and request a instance of a interface/class.
+The following example register a singleton class and then request it multiple times.
+In this example, the class is instantiante in the first Resolve
call
public class SingletonTest
+{
+ public DateTime Date { get; set; }
+
+ //when creating a instance, set the Date property to DateTime.Now value.
+ public SingletonTest() => Date = DateTime.Now;
+}
+
+static void Main(string[] args)
+{
+ //Registering
+ ServiceLocator.Register<SingletonTest>(LifeStyle.SINGLETON);
+
+ var instanceA = ServiceLocator.Resolve<SingletonTest>();
+
+ Thread.Sleep(1000);
+
+ var instanceB = ServiceLocator.Resolve<SingletonTest>();
+
+ Thread.Sleep(1000);
+
+ var instanceC = ServiceLocator.Resolve<SingletonTest>();
+
+ //check that all 3 instances has the same Date.
+}
+
+The following create a new instance for every Resolve
call
+public class TransientTest
+{
+ public DateTime Date { get; set; }
+
+ //when creating a instance, set the Date property to DateTime.Now value.
+ public TransientTest() => Date = DateTime.Now;
+}
+
+static void Main(string[] args)
+{
+ //Registering
+ ServiceLocator.Register<TransientTest>();
+
+ var instanceA = ServiceLocator.Resolve<TransientTest>();
+
+ Thread.Sleep(1000);
+
+ var instanceB = ServiceLocator.Resolve<TransientTest>();
+
+ Thread.Sleep(1000);
+
+ var instanceC = ServiceLocator.Resolve<TransientTest>();
+
+ //check that all 3 instances has different Date properties value.
+}
+
+
+
+
+
+
+
+