Rebus.Async with SimpleInjector Request/Reply MessageCouldNotBeDispatchedToAnyHandlersException - c#

I'm using Rebus.Async to reply a processing data to WebApi request using command CQRS.
1. I registered bus with the following configuration:
public static IContainerRegistry RegisterRebusInMemory(
this IContainerRegistry containerRegistry)
{
switch (_containerAdapter)
{
default: // SimpleInjector
return RegisterRebusInMemoryWithSimpleInjectorContainer(containerRegistry);
}
}
private static IContainerRegistry RegisterRebusInMemoryWithSimpleInjectorContainer(
IContainerRegistry containerRegistry)
{
var rebusQueue = "rebusMessages";
Container container = (Container)containerRegistry.Container;
RegisterRebus(containerRegistry);
container.ConfigureRebus(
configurer => configurer
.Logging(l => l.Console())
.Serialization(s => s.UseNewtonsoftJson(NewtonsoftSettings, Encoding.UTF8))
.Options(o =>
{
o.EnableSynchronousRequestReply();
o.SetNumberOfWorkers(1);
o.SetMaxParallelism(1);
})
.Transport(t => t.UseInMemoryTransport(new InMemNetwork(), rebusQueue))
.Routing(r =>
{
r.TypeBased()
.MapAssemblyOf<IDomainNotification>(rebusQueue)
.MapAssemblyOf<DefaultReplyCommand>(rebusQueue)
.MapCommands(rebusQueue)
.MapEvents(rebusQueue);
})
.Sagas(sagas => sagas.StoreInMemory())
.Subscriptions(s => s.StoreInMemory())
.Start()
);
return containerRegistry;
}
2. I create a Handle to use with request/reply:
public class MyCommandHandler : CommandHandler, IHandleMessages<MyCommand>
{
...
public async Task Handle(MyCommand message)
{
DefaultReplyCommand defaultReply = new DefaultReplyCommand(message.AggregateId);
// Do some stuffs
await _bus.Reply(_reply);
}
...
}
3. When I send the reply with await _bus.Reply(_reply) throw the following exception:
[WRN] Rebus.Retry.ErrorTracking.InMemErrorTracker (Rebus 1 worker 1): Unhandled exception 1 (FINAL) while handling message with ID "request-reply_3452be37-fdfd-4115-89a2-504b4feae22f" Rebus.Exceptions.MessageCouldNotBeDispatchedToAnyHandlersException: Message with ID request-reply_3452be37-fdfd-4115-89a2-504b4feae22f and type AgroHUB.Application.Cattle.Commands.CattleOperation.MoveCattleOperationCommand, AgroHUB.Application.Cattle could not be dispatched to any handlers (and will not be retried under the default fail-fast settings)
at Rebus.Pipeline.Receive.DispatchIncomingMessageStep.Process(IncomingStepContext context, Func`1 next)
at Rebus.Sagas.LoadSagaDataStep.Process(IncomingStepContext context, Func`1 next)
at Rebus.Pipeline.Receive.ActivateHandlersStep.Process(IncomingStepContext context, Func`1 next)
at Rebus.Internals.ReplyHandlerStep.Process(IncomingStepContext context, Func`1 next)
at Rebus.Pipeline.Receive.HandleRoutingSlipsStep.Process(IncomingStepContext context, Func`1 next)
at Rebus.Pipeline.Receive.DeserializeIncomingMessageStep.Process(IncomingStepContext context, Func`1 next)
at Rebus.DataBus.ClaimCheck.HydrateIncomingMessageStep.Process(IncomingStepContext context, Func`1 next)
at Rebus.Pipeline.Receive.HandleDeferredMessagesStep.Process(IncomingStepContext context, Func`1 next)
at Rebus.Retry.FailFast.FailFastStep.Process(IncomingStepContext context, Func`1 next)
at Rebus.Retry.Simple.SimpleRetryStrategyStep.DispatchWithTrackerIdentifier(Func`1 next, String identifierToTrackMessageBy, ITransactionContext transactionContext, String messageId, String secondLevelMessageId)
Cenario
The Rebus.Async works with native C# Dependency Injection (service.AddScope), but when I change de Cointainer to use Simple Injector the reply doesn't work anymore.
There's some extra configuration to use Rebus.Async with Simple Injector?

Related

Autofac.Core.Registration.ComponentNotRegisteredException even the interface seems to be registered

I try to implement a WPF application using dependency injection and the MVVM pattern using the frameworks "CommunityFramework.MVVM" and "Autofac".
What I have so far is the the following(shows only the required parts):
in Main Project.
Namespace: .UI.WPF
public class App : Application
{
private IContainer _container;
public App()
{
_builder = new ContainerBuilder();
var assembly = Assembly.GetAssembly(typeof(Installer));
string fullPath = assembly!.Location;
string dir = Path.GetDirectoryName(fullPath)!;
_builder.RegisterAssemblyModules(assembly);
var assemblyPath = Path.Combine(dir, "ViewModel.dll");
Debug.Assert(File.Exists(assemblyPath));
assembly = Assembly.LoadFile(assemblyPath);
_builder.RegisterAssemblyModules(assembly);
assemblyPath = Path.Combine(dir, "Model.dll");
Debug.Assert(File.Exists(assemblyPath));
assembly = Assembly.LoadFile(assemblyPath);
builder.RegisterAssemblyModules(assembly);
_container = _builder.Build();
}
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var start = _container?.Resolve<IShell<IMainWindow>>();
// HERE the Exception occcures !!!
var workSpace = _container?.Resolve<IMainWindowViewModel>();
....
}
}
public interface IShell<T> where T:class
{
// some defines here
}
public class Shell : IShell<IMainWindow>
{
public Shell()
{
// some initialization here
}
}
public class Installer : Module
{
protected override void Load(ContainerBuilder builder)
{
// Shell
object ret = builder.RegisterType<Shell>()
.As<IShell<IMainWindow>>()
.SingleInstance();
// Messanger
builder.Register(_ => MessageListener.Listen().Messenger)
.As<IMessenger>()
.SingleInstance();
}
}
in Project ViewModel:
Namespace: .ViewModel
public class Installer : Module
{
protected override void Load(ContainerBuilder builder)
{
// MainWindowViewModel
builder.RegisterType<MainWindowViewModel>()
.As<IMainWindowViewModel>()
. SingleInstance();
}
}
public interface IMainWindowViewModel
{
// some entries here
}
public class MainWindowViewModel : ObservableRecipient, IMainWindowViewModel
{
private IMessenger _messenger;
private IMyProjectData_data;
public MainWindowViewModel(IMyProjectDatadata, IMessenger messenger)
: base(messenger)
{
_data = data;
_messenger = messenger;
}
}
in Project Model:
Namespace: .Models
public class Installer : Module
{
protected override void Load(ContainerBuilder builder)
{
// Foto-Renamer Data
builder.RegisterType<MyProjectData>()
.As<IMyProjectData>()
.SingleInstance();
// Setings
builder.RegisterType<Settings>()
.As<ISettings>().
SingleInstance();
}
}
public interface IMyProjectData
{
// some entries here
}
public partial class MyProjectData : ObservableObject, IMyProjectData
{
private ISettings _settings;
public MyProjectData(ISettings settings)
{
_settings = settings;
// more initialization here
}
}
public interface ISettings
{
// some entries here
}
public class Settings : ISettings
{
private IShell<IWindow> _shell;
public Settings(IShell<IMainWindow> shell)
{
_shell = shell;
//more initializations here
}
}
At the marked Point i get the following exeption:
EDIT:
Exception:
Autofac.Core.DependencyResolutionException: "An exception was thrown while activating MyProject.ViewModel.MainWindowViewModel."
Stack trace:
at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action1 next) at Autofac.Core.Resolving.Middleware.SharingMiddleware.<>c__DisplayClass5_0.<Execute>b__0() at Autofac.Core.Lifetime.LifetimeScope.CreateSharedInstance(Guid id, Func1 creator)
at Autofac.Core.Lifetime.LifetimeScope.CreateSharedInstance(Guid primaryId, Nullable1 qualifyingId, Func1 creator)
at Autofac.Core.Resolving.Middleware.SharingMiddleware.Execute(ResolveRequestContext context, Action1 next) at Autofac.Core.Resolving.Middleware.CircularDependencyDetectorMiddleware.Execute(ResolveRequestContext context, Action1 next)
at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, ResolveRequest request)
at Autofac.Core.Resolving.ResolveOperation.ExecuteOperation(ResolveRequest request)
at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable1 parameters, Object& instance) at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable1 parameters)
at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters)
at MyProject.UI.WPF.App.OnStartup(StartupEventArgs e) in F:\Projects\MyProject\UI\MyProject.UI.WPF\App.xaml.cs: Zeile64
at System.Windows.Application.<.ctor>b__1_0(Object unused)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
at MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
Inner exeption:
Autofac.Core.DependencyResolutionException: "None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'MyProject.ViewModel.MainWindowViewModel' can be invoked with the available services and parameters:
Cannot resolve parameter 'MyProject.Model.Interfaces.IMyProjectData data' of constructor 'Void .ctor(MyProject.Model.Interfaces.IMyProjectData, CommunityToolkit.Mvvm.Messaging.IMessenger)'."
Stack trace inner exception:
at Autofac.Core.Activators.Reflection.ReflectionActivator.<>c__DisplayClass12_0.b__0(ResolveRequestContext ctxt, Action1 next) at Autofac.Core.Resolving.Middleware.DisposalTrackingMiddleware.Execute(ResolveRequestContext context, Action1 next)
at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
I checked that all three "Installer"-classes are reached and the registration is executed properly.
At the point of the exception I tryed the container: All servicec can be resolved, expected:
_container.Resolve<IMyProjectData>() and
_container.Resolve<ISettings>()
(this is required as parameter for IMyProjectData.ctor)
Can anybody see why the exception raises? It seems I'm blind for the moment!
Thank you in advance for your response.
The problem is that you have 2 instances of FotoRenamer.Model.dll loaded.
If you set a breakpoint on the faulting line and then open Debug->Windows->Modules you will see it. It's caused by loading the assemblies with Assembly.LoadFile(). The assemblies loaded this way are loaded into different load context (see https://learn.microsoft.com/en-us/dotnet/framework/deployment/best-practices-for-assembly-loading?source=recommendations for details about load contexts).
Since all assemblies are referenced by the main project you don't need to load them. The fix is simple:
public static void InstallAutofac(ContainerBuilder builder)
{
var assembly = Assembly.GetAssembly(typeof(Installer));
builder.RegisterAssemblyModules(assembly);
assembly = Assembly.GetAssembly(typeof(ViewModel.Installer));
builder.RegisterAssemblyModules(assembly);
assembly = Assembly.GetAssembly(typeof(Model.Installer));
builder.RegisterAssemblyModules(assembly);
}

Blazor server and Google Auth

I tried to implement google auth to my blazor app. but I received this error:
`ArgumentException: The 'ClientSecret' option must be provided. (Parameter 'ClientSecret')
Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions.Validate()
Microsoft.AspNetCore.Authentication.RemoteAuthenticationOptions.Validate(string scheme)
Microsoft.AspNetCore.Authentication.AuthenticationBuilder+<>c__DisplayClass4_0<TOptions, THandler>.<AddSchemeHelper>b__1(TOptions o)
Microsoft.Extensions.Options.ValidateOptions<TOptions>.Validate(string name, TOptions options)
Microsoft.Extensions.Options.OptionsFactory<TOptions>.Create(string name)
Microsoft.Extensions.Options.OptionsCache<TOptions>+<>c__3<TArg>.<GetOrAdd>b__3_0(string name, ValueTuple<Func<string, TArg, TOptions>, TArg> arg)
System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>.GetOrAdd<TArg>(TKey key, Func<TKey, TArg, TValue> valueFactory, TArg factoryArgument)
Microsoft.Extensions.Options.OptionsCache<TOptions>.GetOrAdd<TArg>(string name, Func<string, TArg, TOptions> createOptions, TArg factoryArgument)
Microsoft.Extensions.Options.OptionsMonitor<TOptions>.Get(string name)
Microsoft.AspNetCore.Authentication.AuthenticationHandler<TOptions>.InitializeAsync(AuthenticationScheme scheme, HttpContext context)
Microsoft.AspNetCore.Authentication.AuthenticationHandlerProvider.GetHandlerAsync(HttpContext context, string authenticationScheme)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
`
And this is my Program.cs
builder.Services.AddAuthentication(options =>
{
}).AddGoogle(options =>
{
options.ClientId = GoogleCredentials.CLientId;
options.ClientSecret = options.ClientSecret;
options.SignInScheme = GoogleDefaults.AuthenticationScheme;
});
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
How can we fix this error?
If someone can help me, reply please.

Using an ILogger in a Polly Policy attached to a Refit Client

I've been trying to follow the directions from this blog post to pass an ILogger to my retry policy in order to log information about the errors being retried.
The code in the blog doesn't work out of the box as we're using Refit for client generation. Based on the refit docs it should just be a matter of adding a property to my method signatures, but haven't been able to get it to actually work.
Even though I've added the property to my method signature:
Task<UserSubscriptions> GetUserSubscriptions(string userId, [Property("PollyExecutionContext")] Polly.Context context);
I've captured logger management in extension methods:
private static readonly string LoggerKey = "LoggerKey";
public static Context WithLogger(this Context context, ILogger logger)
{
context[LoggerKey] = logger;
return context;
}
public static ILogger GetLogger(this Context context)
{
if (context.TryGetValue(LoggerKey, out object logger))
{
return logger as ILogger;
}
return null;
}
I create a new context when executing the method:
public Context GetPollyContext() => new Context().WithLogger(logger);
public Task<UserSubscriptions> GetUserSubscriptions(UserId userId) {
return restClient.GetUserSubscriptions(userId.UserIdString, GetPollyContext());
}
And try to access the logger as part of the retry action:
return Policy
.Handle<Exception>()
.OrResult<HttpResponseMessage>(r => CodesToRetry.Contains(r.StatusCode))
.WaitAndRetryAsync(3, retryCount => TimeSpan.FromSeconds(1), (result, timeSpan, retryCount, context) =>
{
var logger = context.GetLogger();
if (logger == null) return;
// do some logging
}
});
When I set a break point in the retry action the context that I see is a new empty context and not the one I created with the attached logger.
Per GitHub issues, there was a typo, the property is PolicyExecutionContext, not PollyExecutionContext.
Though given I don't need to generate a unique context per request, the better pattern is to use delegate injection.
Extension methods
private static readonly string LoggerKey = "LoggerKey";
public static Context WithLogger(this Context context, ILogger logger)
{
context[LoggerKey] = logger;
return context;
}
public static ILogger GetLogger(this Context context)
{
if (context.TryGetValue(LoggerKey, out object logger))
{
return logger as ILogger;
}
return null;
}
Delegate definition
public class PollyContextInjectingDelegatingHandler<T> : DelegatingHandler
{
private readonly ILogger<T> _logger;
public PollyContextInjectingDelegatingHandler(ILogger<T> logger)
{
_logger = logger;
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
var pollyContext = new Context().WithLogger(_logger);
request.SetPolicyExecutionContext(pollyContext);
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
}
Then add the delegate to the client definition
services
.AddTransient<ISubscriptionApi, SubscriptionApi>()
.AddTransient<PollyContextInjectingDelegatingHandler<SubscriptionApi>>()
.AddRefitClient<ISubscriptionApiRest>(EightClientFactory.GetRefitSettings())
.ConfigureHttpClient((s, c) =>
{
...
})
.AddHttpMessageHandler<PollyContextInjectingDelegatingHandler<SubscriptionApi>>()
.ApplyTransientRetryPolicy(retryCount, timeout);

Cast exception when validation failed in Fluent Validation

I have a .net 6 WebApi which I am using Fluent Validation with MediatR. I have everything working when there is no validation errors.
When I force an error I get the following Exception.
Unable to cast object of type 'System.Collections.Generic.Dictionary`2[System.String,System.String[]]' to type 'System.Collections.Generic.IEnumerable`1[FluentValidation.Results.ValidationFailure]'.
at TestMediatR.Behaviours.ValidationBehaviour`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestPostProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestPreProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at WebApi.Controllers.v1.OrdersController.AddOrder(OrderTicketDto model) in D:\Git Repositories\Current\Web-Sites\RestWebApi\src\WebApi\Controllers\v1\OrdersController.cs:line 36
Code executing the mediatR send is this.
[HttpPost("AddOrder")]
public async Task<IActionResult> AddOrder([FromBody] OrderTicketDto model)
{
_logger.LogInformation("Adding Order: {#model}", model);
try
{
var response = await Mediator.Send(new AddOrderCommand()
{
OrderData = model.OrderTicket,
Url = model.SiteUrl,
Token = model.Token
});
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Add Order Error"); //<------ FluentValidation exception caught here
return BadRequest(ex.Message);
}
}
and validation for the command executed above is done like this
public class AddOrderCommandValidator : AbstractValidator<AddOrderCommand>
{
public AddOrderCommandValidator()
{
RuleFor(x => x.Url)
.NotEmpty()
.NotNull();
RuleFor(x => x.Token)
.NotEmpty()
.NotNull();
RuleFor(x => x.OrderData)
.NotNull();
}
}
Register of the validators is done here in startup
public static IServiceCollection AddPiKSRestValidators(this IServiceCollection services)
{
var domainAssembly = typeof(GetTablesCommandValidator).GetTypeInfo().Assembly;
//Add FluentValidation
services.AddValidatorsFromAssembly(domainAssembly);
return services;
}
As I say, everything works when I pass valid properties, but force it to be invalid by setting say Token property to null and I get the exception.
Feel like I am missing something.
So the issue was with the ValidationBehaviour
here is the code to report the errors
public class ValidationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : notnull, IRequest<TResponse>
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
private readonly ILogger<TRequest> _logger;
public ValidationBehaviour(IEnumerable<IValidator<TRequest>> validators, ILogger<TRequest> logger)
{
_validators = validators;
_logger = logger;
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
if (_validators.Any())
{
var context = new ValidationContext<TRequest>(request);
var errorsDictionary = _validators
.Select(x => x.Validate(context))
.SelectMany(x => x.Errors)
.Where(x => x != null)
.GroupBy(
x => x.PropertyName,
x => x.ErrorMessage,
(propertyName, errorMessages) => new
{
Key = propertyName,
Values = errorMessages.Distinct().ToArray()
})
.ToDictionary(x => x.Key, x => x.Values);
if (errorsDictionary.Any())
{
throw new ValidationException((IEnumerable<FluentValidation.Results.ValidationFailure>)errorsDictionary);
}
}
else
_logger.LogDebug("No Validators found");
return await next();
}
}
As you can see a dictionary is trying to be cast to (IEnumerable<FluentValidation.Results.ValidationFailure>)
fixed with this.
var errorsDictionary = _validators
.Select(x => x.Validate(context))
.SelectMany(x => x.Errors)
.Where(x => x != null)
.GroupBy(x => new {x.PropertyName, x.ErrorMessage })
.Select(x => x.FirstOrDefault())
.ToList();
if (errorsDictionary.Any())
{
throw new ValidationException(errorsDictionary);
}

Configure Simple Injector to support resolving ASP.NET Core middleware dependencies?

How can I configure SimpleInjector to resolve LogMiddleware's Invoke method dependency, like IMessageService ?
As I know, Asp.net core uses HttpContext.RequestServices (IServiceProvider) to resolve dependencies, I set SimpleInjector container to HttpContext.RequestServices property but didn't work. I want to change ServiceProvider dynamically because each tenant should have a container.
public class LogMiddleware
{
RequestDelegate next;
private readonly ILogger log;
public LogMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
{
this.next = next;
this.log = loggerFactory.CreateLogger<LogMiddleware>();
}
public async Task Invoke(HttpContext context, IMessageService messageService)
{
await context.Response.WriteAsync(
messageService.Format(context.Request.Host.Value));
}
}
public interface IMessageService
{
string Format(string message);
}
public class DefaultMessageService : IMessageService
{
public string Format(string message)
{
return "Path:" + message;
}
}
You can use your LogMiddleware class as follows:
applicationBuilder.Use(async (context, next) => {
var middleware = new LogMiddleware(
request => next(),
applicationBuilder.ApplicationServices.GetService<ILoggerFactory>());
await middleware.Invoke(context, container.GetInstance<IMessageService>());
});
I however advise you to change your middleware class a little bit. Move the runtime data (the next() delegate) out of the constructor (since components should not require runtime data during construction), and move the IMessageService dependency into the constructor. And replace the ILoggerFactory with a ILogger dependency, since an injection constructor should do no more than store its incoming dependencies (or replace ILogger with your own application-specific logger abstraction instead).
Your middleware class will then look as follows:
public sealed class LogMiddleware
{
private readonly IMessageService messageService;
private readonly ILogger log;
public LogMiddleware(IMessageService messageService, ILogger log) {
this.messageService = messageService;
this.log = log;
}
public async Task Invoke(HttpContext context, Func<Task> next) {
await context.Response.WriteAsync(
messageService.Format(context.Request.Host.Value));
await next();
}
}
This allows you to use your middleware as follows:
var factory = applicationBuilder.ApplicationServices.GetService<ILoggerFactory>();
applicationBuilder.Use(async (context, next) => {
var middleware = new LogMiddleware(
container.GetInstance<IMessageService>(),
factory.CreateLogger<LogMiddleware>());
await middleware.Invoke(context, next);
});
Or in case you registered the ILogger (or your custom logging abstraction) in Simple Injector, you can do the following:
applicationBuilder.Use(async (context, next) => {
var middleware = container.GetInstance<LogMiddleware>();
await middleware.Invoke(context, next);
});
There is two problem with your code.
Your "DefaultMessageService" does not implement interface "IMessageService".
It should be like this.
public class DefaultMessageService : IMessageService
{
public string Format(string message)
{
return "Path:" + message;
}
}
You have to register DefaultMessageService in ConfigureService in Startup.cs.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddSingleton<IMessageService>(new DefaultMessageService());
}

Categories