I'm currently building a library that contains several OWIN-middlewares. These middlewares should be executed in a certain order. In one of the first releases of OWIN, there was the IAppBuilder interface. However the IAppBuilder is not part of OWIN anymore, but part of Microsoft.Owin. I don't want to force my user(s) to have a dependency on Microsoft.Owin.
What is the preferred way of adding middlewares to the OWIN-pipeline without using Microsoft.Owin?
It took some time, but I think I figured it out.
First the definitions as specified by Owin:
public delegate Task AppFunc(IDictionary<string, object> environment);
public delegate AppFunc MidFunc(AppFunc next);
public delegate MidFunc MidFactory(IDictionary<string, object> startupProperties);
public delegate void BuildFunc(MidFactory midFactory);
I use delegate here to avoid the generics madness.
To go from IAppBuilder to BuildFunc:
public static BuildFunc UseOwin(this IAppBuilder builder)
{
return middleware => builder.Use(middleware(builder.Properties));
}
In order to build a pipeline using BuildFunc, you can create an extension on BuildFunc:
public static BuildFunc UseMyFramework(this BuildFunc buildFunc)
{
buildFunc(startupProperties => BuildPipeline(startupProperties));
return buildFunc;
}
It is a good practice to return the BuildFunc for chaining.
Building the pipeline is nothing more than linking the MidFuncs together and optionally end with the actual AppFunc:
public static MidFunc BuildPipeline(IDictionary<string, object> startupProperties)
{
return next => LogMiddleware(AuthenticateMiddleware(MyApplication));
// Or this if you don't supply your own AppFunc
return next => LogMiddleware(AuthenticateMiddleware(next));
}
public static AppFunc LogMiddleware(AppFunc next)
{
AppFunc middleware = async environment =>
{
// Log request
await next(environment);
};
return middleware;
}
public static AppFunc AuthenticateMiddleware(AppFunc next)
{
AppFunc middleware = async environment =>
{
// authenticate request
await next(environment);
};
return middleware;
}
public static async Task MyApplication(IDictionary<string, object> environment)
{
await Task.CompletedTask;
}
You still need to connect the Owin implementation to your framework. I use Microsoft.Owin for this:
app.UseOwin().UseMyFramework()
Related
I have to do some extra logic layer on existing classes. I'm using autofac.
The project is Windows service having also Kestrel server. Program.cs e.g.
void Main(string[] args) {
var customQueue = new CustomQueue();
var someClass = new SomeClass(customQueue);
var randomClass = new RandomClass();
// do some logic here with using declared instances
var server = new Server(someClass, randomClass);
server.Start();
}
And here is the Server.cs
class Server {
private IWebHost _host;
public Server(SomeClass cls, RandomClass cls1) {
// set to fields
}
void Start() {
_host = new WebHostBuilder()
.UseKestrel()
.ConfigureServices(services =>
{
services.AddAutoFac(); // first as per doc in order to scaffold 'ConfigureContainer'?
services.AddSingleton(someClass); // fields
services.AddSingleton(randomClass); // fields
})
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration(...)
.ConfigureLogging(...);
.UseStartup<Startuo>()
.Build();
_host.StartAsync();
}
}
Startup.cs
public class Startup
{
public ILifetimeScope AutofacContainer { get; private set; }
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// create a container-builder and register dependencies
var builder = new ContainerBuilder();
// populate the service-descriptors added to `IServiceCollection`
// BEFORE you add things to Autofac so that the Autofac
// registrations can override stuff in the `IServiceCollection`
// as needed
builder.Populate(services);
builder.RegisterType<SomeClass>()
.As<ISomeClass>()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(SomeClassInterceptor));
builder.Register(_ => new SomeClassInterceptor());
AutofacContainer = builder.Build();
return new AutofacServiceProvider(AutofacContainer);
}
}
And last SomeClassInterceptor.cs
public class SomeClassInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
try
{
invocation.Proceed();
if (invocation.ReturnValue is Task taskResult)
{
taskResult.ContinueWith(
t =>
{
Console.WriteLine("OOHH YEAHH");
}, TaskContinuationOptions.None);
}
else
{
Console.WriteLine("WOW");
}
}
catch (Exception ex)
{
Console.WriteLine("EXCEPTIOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNN");
}
}
}
I've tried with Named and Typed registration with having Intercept(...) attribute but still no success. Nothing gets triggered.
Also ISomeClass is inheriting other interfaces, I've tried setting .As<>() also with those but no.
What am I missing?
In order to let the interceptor works. The class should be build by Autofac.
services.AddAutofac();
services.AddSingleton(someClass);
services.AddSingleton(randomClass);
In your case you configure Autofac using the AddAutofac method then add SomeClass as a singleton using the AddSingleton which will override the Autofac configuration. There is no way that Autofac can inject the interceptor in it.
If you want to register SomeClass as singleton you should register it using the SingleInstance() method
builder.RegisterType<SomeClass>()
.As<ISomeClass>()
.SingleInstance()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(SomeClassInterceptor));
I need to pass some parameters from middleware to controller and I'm confused which approach should I use if I have to take care of performance, resource usage and security.
context.Items["user-id"] = "12345";
context.Session.SetInt32("user-id", 12345);
(It is the requirement to keep the Session enabled anyway.)
You could pass it as an http header down the pipeline with the request
public class UserHeaderMiddleware
{
private readonly RequestDelegate _next;
public UserHeaderMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
context.Request.Headers.Add("user-id", new[] { userId.ToString() });
await _next(context);
}
}
If you need to store the user ID for the future, session is the way to go. Items only passes it along for that request.
I have a Service Fabric asp.net core stateless service which implements custom middleware. In that middleware I need access to my service instance. How would I go about injecting this using asp.net core's built-in DI/IoC system?
public class MyMiddleware
{
private readonly RequestDelegate _next;
public MyMiddleware(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext httpContext)
{
// ** need access to service instance here **
return _next(httpContext);
}
}
Someone mentioned accomplishing this using TinyIoC in Web Api 2 in the Apr 20, 2017 Q&A #11 [45:30] with the Service Fabric team. As well that the current recommended method is to use asp.net core.
Any help or examples would be greatly appreciated!
In the asp.net core stateless service that creates the ServiceInstanceListener you can inject the context like this:
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new[]
{
new ServiceInstanceListener(serviceContext =>
new WebListenerCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
{
logger.LogStatelessServiceStartedListening<WebApi>(url);
return new WebHostBuilder().UseWebListener()
.ConfigureServices(
services => services
.AddSingleton(serviceContext) // HERE IT GOES!
.AddSingleton(logger)
.AddTransient<IServiceRemoting, ServiceRemoting>())
.UseContentRoot(Directory.GetCurrentDirectory())
.UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
.UseStartup<Startup>()
.UseUrls(url)
.Build();
}))
};
}
Your middleware than can use it like this:
public class MyMiddleware
{
private readonly RequestDelegate _next;
public MyMiddleware(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext httpContext, StatelessServiceContext serviceContext)
{
// ** need access to service instance here **
return _next(httpContext);
}
}
For a complete example take a look at this repository: https://github.com/DeHeerSoftware/Azure-Service-Fabric-Logging-And-Monitoring
Points of interest for you:
Setting up the DI: https://github.com/DeHeerSoftware/Azure-Service-Fabric-Logging-And-Monitoring/blob/master/src/WebApi/WebApi.cs
Using context in middleware: https://github.com/DeHeerSoftware/Azure-Service-Fabric-Logging-And-Monitoring/blob/master/src/ServiceFabric.Logging/Middleware/RequestTrackingMiddleware.cs
Dependency injection via constructor works for middleware classes as well as for others. Just add additional parameters to the middleware constructor
public MyMiddleware(RequestDelegate next, IMyService myService)
{
_next = next;
...
}
But also you can add dependency directly to the Invoke method
Documentation: Because middleware is constructed at app startup, not per-request, scoped lifetime services used by middleware constructors are not shared with other dependency-injected types during each request. If you must share a scoped service between your middleware and other types, add these services to the Invoke method's signature. The Invoke method can accept additional parameters that are populated by dependency injection.
public class MyMiddleware
{
private readonly RequestDelegate _next;
public MyMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext, IMyScopedService svc)
{
svc.MyProperty = 1000;
await _next(httpContext);
}
}
I know that the services get wired-up by instantiating the BasicAppHost, and the IoC by using the ConfigureContainer property, but where is the right place to add the filters? The test in question never fire the global filter:
[TestFixture]
public class IntegrationTests
{
private readonly ServiceStackHost _appHost;
public IntegrationTests()
{
_appHost = new BasicAppHost(typeof(MyServices).Assembly)
{
ConfigureContainer = container =>
{
//
}
};
_appHost.Plugins.Add(new ValidationFeature());
_appHost.Config = new HostConfig { DebugMode = true };
_appHost.GlobalRequestFilters.Add(ITenantRequestFilter);
_appHost.Init();
}
private void ITenantRequestFilter(IRequest req, IResponse res, object dto)
{
var forTennant = dto as IForTenant;
if (forTennant != null)
RequestContext.Instance.Items.Add("TenantId", forTennant.TenantId);
}
[TestFixtureTearDown]
public void TestFixtureTearDown()
{
_appHost.Dispose();
}
[Test]
public void CanInvokeHelloServiceRequest()
{
var service = _appHost.Container.Resolve<MyServices>();
var response = (HelloResponse)service.Any(new Hello { Name = "World" });
Assert.That(response.Result, Is.EqualTo("Hello, World!"));
}
[Test]
public void CanInvokeFooServiceRequest()
{
var service = _appHost.Container.Resolve<MyServices>();
var lead = new Lead
{
TenantId = "200"
};
var response = service.Post(lead); //Does not fire filter.
}
}
ServiceStack is set at 4.0.40
Updated
After perusing the ServiceStack tests (which I highly recommend BTW) I came across a few example of the AppHost being used AND tested. It looks like the "ConfigureAppHost" property is the right place to configure the filters, e.g.
ConfigureAppHost = host =>
{
host.Plugins.Add(new ValidationFeature());
host.GlobalRequestFilters.Add(ITenantRequestFilter);
},
ConfigureContainer = container =>
{
}
Updated1
And they still don't fire.
Updated2
After a bit of trial and error I think it's safe to say that NO, the filters are not hooked up while using the BasicAppHost. What I have done to solve my problem was to switch these tests to use a class that inherits from AppSelfHostBase, and use the c# servicestack clients to invoke the methods on my service. THIS does cause the global filters to be executed.
Thank you,
Stephen
No the Request and Response filters only fire for Integration Tests where the HTTP Request is executed through the HTTP Request Pipeline. If you need to test the full request pipeline you'd need to use a Self-Hosting Integration test.
Calling a method on a Service just does that, i.e. it's literally just making a C# method call on a autowired Service - there's no intermediate proxy magic intercepting the call in between.
I have the following (here simplified) code which I want to test with FakeItEasy.
public class ActionExecutor : IActionExecutor
{
public void TransactionalExecutionOf(Action action)
{
try
{
// ...
action();
// ...
}
catch
{
// ...
Rollback();
}
}
public void Commit()
{ }
public void Rollback()
{ }
}
public class Service : IService
{
private readonly IRepository _repository;
private readonly IActionExecutor _actionExecutor;
// ctor for CI
public void ServiceMethod(string name)
{
_actionExecutor.TransactionalExecutionOf(() =>
{
var item = _repository.FindByName(ItemSpecs.FindByNameSpec(name));
if (item == null) throw new ServiceException("Item not found");
item.DoSomething();
_actionExecutor.Commit();
}
}
}
I want to test that the ServiceException is thrown so i setup my test like that
var repo = A.Fake<IRepository>();
A.CallTo(() => repo.FindByName(A<ISpec<Item>>.Ignored))
.Returns(null);
var executor = A.Fake<IActionExecutor>();
executor.Configure()
.CallsTo(x => x.Rollback()).DoesNothing();
executor.Configure()
.CallsTo(x => x.Commit()).DoesNothing();
executor.Configure()
.CallsTo(x => x.TransactionalExecutionOf(A<Action>.Ignored))
.CallsBaseMethod();
With the following code
var service = new Service(executor, repo);
service.ServiceMethod("notExists")
.Throws(new ServiceException());
I get the following message
The current proxy generator can not intercept the specified method
for the following reason:
- Sealed methods can not be intercepted.
If I call the method directly on the service like
var service = new Service(executor, repo);
service.ServiceMethod("NotExists");
I get this message
This is a DynamicProxy2 error: The interceptor attempted to 'Proceed'
for method 'Void TransactionalExecutionOf(System.Action)' which has no
target. When calling method without target there is no implementation
to 'proceed' to and it is the responsibility of the interceptor to
mimic the implementation (set return value, out arguments etc)
Now I am a bit confused and don't know what to do next.
Problems comes from the way you create fake and what you later expect it to do:
var executor = A.Fake<IActionExecutor>();
// ...
executor.Configure()
.CallsTo(x => x.TransactionalExecutionOf(A<Action>.Ignored))
.CallsBaseMethod();
What base method? FakeItEasy has no idea what the base class is, and hence the DynamicProxy2 exception in your second case. You can create partial mock this way:
var executor = A.Fake<ActionExecutor>();
Note that we're basing on actual implementation, not interface anymore
This however introduces a new set of problems, as methods on ActionExecutor are not virtual and therefore interceptor cannot hook up to well - intercept them. To make your current setup work, you'll have to change your ActionExecutor and make (all) the methods virtual.
However, you may (or even should) want to avoid modifications of existing code (which sometimes might not even be an option). You could then set up your IActionExecutor fake like this:
var executor = A.Fake<IActionExecutor>();
A.CallTo(() => executor.TransactionalExecutionOf(A<Action>.Ignored))
.Invokes(f => new ActionExecutor()
.TransactionalExecutionOf((Action)f.Arguments.First())
);
This will allow you to work on faked object, with the exception of call to TransactionalExecutionOf which will be redirected to actual implementation.