Skip to content

Commit

Permalink
Sample middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
aritchie committed Jun 3, 2024
1 parent bd678dc commit db0fbb4
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 36 deletions.
2 changes: 2 additions & 0 deletions Sample/EventPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
<Span Text="{Binding Arg, StringFormat='Arg: {0}'}" />
<Span Text=" - " />
<Span Text="{Binding FireAndForget, StringFormat='Fire and Forget: {0}'}" />
<Span Text=" - " />
<Span Text="{Binding ElapsedMillis, StringFormat='{0} ms'}" />
</FormattedString>
</Label.FormattedText>
</Label>
Expand Down
2 changes: 2 additions & 0 deletions Sample/EventViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ AppSqliteConnection conn
x.Area,
x.Arg,
x.FireAndForget,
x.ExecutionTimeMillis,
x.Timestamp.ToLocalTime().ToString("g")
))
.ToList();
Expand Down Expand Up @@ -48,5 +49,6 @@ public record EventItemViewModel(
string Area,
string Arg,
bool FireAndForget,
long ElapsedMillis,
string Timestamp
);
1 change: 1 addition & 0 deletions Sample/MauiProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public static MauiApp CreateMauiApp()
builder.Services.AddShinyMediator(x => x.UseMaui());
builder.Services.AddSingletonAsImplementedInterfaces<SingletonEventHandler>();
builder.Services.AddSingletonAsImplementedInterfaces<SingletonRequestHandler>();
builder.Services.AddSingletonAsImplementedInterfaces<MyRequestMiddleware>();

builder.Services.AddSingleton<AppSqliteConnection>();
builder.Services.AddMauiBlazorWebView();
Expand Down
29 changes: 17 additions & 12 deletions Sample/MyRequestMiddleware.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
using System.Diagnostics;

namespace Sample;


// [RegisterMiddleware]
public class MyRequestMiddleware : IRequestMiddleware<MyMessageRequest, MyMessageResponse>
public class MyRequestMiddleware(AppSqliteConnection conn) : IRequestMiddleware<MyMessageRequest, MyMessageResponse>
{
public async Task<MyMessageResponse> Process(MyMessageRequest request, Func<Task<MyMessageResponse>> next, CancellationToken cancellationToken)
{
// BEFORE - If connected - pull from API after save to cache ELSE pull from cache
var result = await next();
// AFTER = cache
var sw = new Stopwatch();
sw.Start();
var result = await next().ConfigureAwait(false);
sw.Stop();

await conn.Log(
nameof(MyRequestMiddleware),
new MyMessageEvent(
request.Arg,
request.FireAndForgetEvents
),
sw.ElapsedMilliseconds
);
return result;
}
}

public class CatchAllRequestMiddleware : IRequestMiddleware<IRequest<object>, object>
{
public Task<object> Process(IRequest<object> request, Func<Task<object>> next, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
6 changes: 4 additions & 2 deletions Sample/Services/AppSqliteConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ public AppSqliteConnection(IPlatform platform) : base(Path.Combine(platform.AppD
data.CreateTable<LogModel>();
}

public Task Log(string area, MyMessageEvent @event) => this.InsertAsync(new LogModel
public Task Log(string area, MyMessageEvent @event, long executionTimeMillis = 0) => this.InsertAsync(new LogModel
{
Area = area,
Arg = @event.Arg,
FireAndForget = @event.FireAndForgetEvents,
Timestamp = DateTimeOffset.UtcNow
Timestamp = DateTimeOffset.UtcNow,
ExecutionTimeMillis = executionTimeMillis
});
public AsyncTableQuery<LogModel> Logs => this.Table<LogModel>();
}
Expand All @@ -30,5 +31,6 @@ public class LogModel
public string Area { get; set; }
public string Arg { get; set; }
public bool FireAndForget { get; set; }
public long ExecutionTimeMillis { get; set; }
public DateTimeOffset Timestamp { get; set; }
}
19 changes: 7 additions & 12 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,29 +155,24 @@ public class MyViewModel : BaseViewModel,
}
```

## Request Middleware
TODO

## Event Covariance
TODO

## Sample
There is a sample in this repo. You do not need any other part of Shiny, Prism, ReactiveUI, etc - those are included as I write things faster with it.
Focus on the interfaces from the mediator & the mediator calls itself

## Ideas for Workflows
## Ideas for Workflows Request & Events
* Use Prism with Modules - want strongly typed navigation parameters, navigations, and have them available to other modules - we're the guy to help!
* Example TBD
* Using a Shiny Foreground Job - want to push data an event that new data came in to anyone listening?
* Have a Shiny Push Delegate that is executing on the delegate but want to push it to the UI, Mediator has a plan!

## Request Middleware Ideas
* Connectivity check - pull from cache/memory or go to the API

## TODO
* Explain Event Collectors
* Document
* Event Collectors
* Request Middleware
* Covariance Event Handlers & Request Middleware
* OOBE Middleware
* Event Collectors for MAUI execute on main thread?
* Streams - IAsyncEnumerable or IObservable
* Source Generator Registration
* Need to use a different method or not use extension methods - maybe AddHandlersFromAssemblyName or allow it to be custom named
* IEventHandler<IEvent> can handle ALL events?
* Need to use a different method or not use extension methods - maybe AddHandlersFromAssemblyName or allow it to be custom named
11 changes: 6 additions & 5 deletions src/Shiny.Mediator/Impl/DefaultRequestSender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,13 @@ async Task<TResult> ExecuteMiddleware<TRequest, TResult>(
CancellationToken cancellationToken
) where TRequest : IRequest<TResult>
{
// var middlewareType = typeof(IRequestMiddleware<,>).MakeGenericType(request.GetType(), typeof(TResult));
// var middlewareMethod = middlewareType.GetMethod("Process", BindingFlags.Instance | BindingFlags.Public)!;
// var middlewares = scope.ServiceProvider.GetServices(middlewareType).ToList();
// var pipeline = new List<Func<Task<TResult>>> { initialExecute };
var middlewareType = typeof(IRequestMiddleware<,>).MakeGenericType(request.GetType(), typeof(TResult));
var middlewareMethod = middlewareType.GetMethod("Process", BindingFlags.Instance | BindingFlags.Public)!;
var middlewares = scope.ServiceProvider.GetServices(middlewareType).ToList();
var pipeline = new List<Func<Task<TResult>>> { initialExecute };

// we get the middleware reverse ordered from last to first so execution
// Unable to find seq points for method 'System.Runtime.CompilerServices.AsyncMethodBuilderCore:Start<Sample.MyRequestMiddleware/<Process>d__2> (Sample.MyRequestMiddleware/<Process>d__2&)', offset 0xfffffe88.
// we get the middleware reverse ordered from last to first so execution ordered properly
// middlewares.Reverse();
// foreach (var middleware in middlewares)
// {
Expand Down
6 changes: 1 addition & 5 deletions tests/Shiny.Mediator.Tests/MiddlewareTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,11 @@ public MiddlewareTests()
public async Task ConstrainedAndOpen(bool addConstrained, bool addOpen)
{
var services = new ServiceCollection();
services.AddShinyMediator(cfg =>
{

});
services.AddShinyMediator();
services.AddSingletonAsImplementedInterfaces<MiddlewareRequestResultHandler>();

if (addConstrained)
services.AddSingleton<IRequestMiddleware<MiddlewareResultRequest, int>, ConstrainedMiddleware>();
//services.AddSingletonAsImplementedInterfaces<ConstrainedMiddleware>();

if (addOpen)
services.AddSingleton(typeof(IRequestMiddleware<,>), typeof(VariantRequestMiddleware<,>));
Expand Down

0 comments on commit db0fbb4

Please sign in to comment.