How do I get OWIN to host a SOAP endpoint (do not care if WCF is or isn't involved, SOAP gives WSDL which makes services easier to consume by certain clients, that's why I want SOAP and REST)
I suspect the answer is: Implement your own middleware that hosts a SOAP endpoint. If that's the answer so be it, but that's a lot of work so I'll probably just end up sticking with WCF and avoiding OWIN if that's the case. I find it hard to believe no one has implemented a SOAP hosting middleware yet...
As a rule we like to do both REST and SOAP endpoints on our services; currently we use IIS and the WCF restful bits to host the SOAP with [ServiceContract]/[OperationContract] attributes, and the rest is defined with [WebInvoke] attributes, with these attributes the services need no reimplementation for the different endpoint types.
We just use the ASP.NET routes to add new ServiceRoutes which add a rest binding to URI/REST with the same service as a soap binding to URI/SOAP.
Now we're looking at doing some new services work and I'd like to move forward to using OWIN so we can implement our new services with hosting agnosticism as some services will be better served by windows service hosting and some better served by IIS service hosting.
All of my fiddling with things and so far I can come up with no way of getting a SOAP endpoint hosted by OWIN. I have the rest handled fine by making my service inherit from ApiController and then using this little snippet of code in the OWIN app's Configuration method:
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
app.UseWebApi(config);
[...]
There is a custom OWIN middleware example on MSDN that shows how to support SOAP requests. It is not a general purpose WCF host but may be enough to expose your existing WCF Services (i.e. [ServiceContract/OperationContract]) within an ASP.NET Core app. The example does not include support for [WebGet/WebInvoke] but may be enough to get you started.
https://blogs.msdn.microsoft.com/dotnet/2016/09/19/custom-asp-net-core-middleware-example/
If your primary goal is simply to begin writing new services using OWIN and you still plan to host them in IIS using Microsoft.Owin.Host.SystemWeb. You could ignore the WCF requests within the OWIN pipeline and allow the IIS ASP.NET pipeline to handle them. This would enable you to write services that are a combination of OWIN middleware and traditional WCF endpoints.
public static class WCFAppBuilderExtensions
{
public static IAppBuilder IgnoreWCFRequests(this IAppBuilder builder)
{
return builder.MapWhen(context => IsWCFRequest(context), appBuilder =>
{
// Do nothing and allow the IIS ASP.NET pipeline to process the request
});
}
private static bool IsWCFRequest(IOwinContext context)
{
// Determine whether the request is to a WCF endpoint
return context.Request.Path.Value.EndsWith(".svc", StringComparison.OrdinalIgnoreCase);
}
}
Then call the IgnoreWCFRequests extension method when configuring your app.
public class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
WebApiConfig.Register(config);
app
.IgnoreWCFRequests()
.UseWebApi(config)
.Run(context =>
{
return context.Response.WriteAsync("Default Response");
});
}
}
It's not so easy to host a WCF infrastructure over an OWIN one, sure it can be possible, with a bit of work it's clear possible to adapt, or proxy the owing request-response layer to the WCF infrastructure; WCF provides a not so easy but a complete infrastructure to do something like that.
cpowers answer may work for some, but didn't for me because I have other Filesystems setup within Owin, and I couldn't get both behaviors (fallback to other handlers when needed and also go through OWIN pipelines).
This was the configuration which made it work for me:
Use Owin automatic startup (Remove any appSettings named owin:AutomaticAppStartup)
Do not manually add its handlers in your web.config (or Startup will run twice) (Remove OwinHttpHandlerfrom from <handlers> in you web.config)
Add appBuilder.UseStageMarker(PipelineStage.MapHandler) after builder.UseFileServer()
UseFileServer must happen after all pipelines you setup, otherwise the ones setup after it will not work and you'll get 404
Optionally Fork the pipeline like cpower mentioned
If your OWIN pipelines does not register middlewares for the paths where your legacy stuff is you don't even need to fork your pipeline (my case).
Related
I am reading the Autofac documentation related to its integration with OWIN, and I get confused by the example they put on their website:
public class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
// STANDARD WEB API SETUP:
// Get your HttpConfiguration. In OWIN, you'll create one
// rather than using GlobalConfiguration.
var config = new HttpConfiguration();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// Run other optional steps, like registering filters,
// per-controller-type services, etc., then set the dependency resolver
// to be Autofac.
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// OWIN WEB API SETUP:
// Register the Autofac middleware FIRST, then the Autofac Web API middleware,
// and finally the standard Web API middleware.
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
}
}
Where I am stuck now is on line config.DependencyResolver = new AutofacWebApiDependencyResolver(container); the webapi dependency resolver is set to autofac, and what is the reason that app.UseAutofacWebApi(config); must be called?
The extension method is to "Extends the Autofac lifetime scope added from the OWIN pipeline through to the Web API dependency scope", but the autofac lifetime scope is shared by setting dependency resolver, is this call still necessary?
It would also be very helpful if you can provide me the use cases of UseAutofacWebApi. Thanks!
The short answer is, yes, it's needed.
Usually a way to test this sort of thing is to see if you can get everything you need without it. I mean, if your app works and things are injected right, that's enough, right?
The longer answer involves you needing to understand that Web API is not natively part of OWIN. OWIN is kind of a bolt-on. The way Web API integrates is, very basically, that the Web API pipeline is jammed into the OWIN pipeline as a middleware step. You can do other stuff with OWIN, too, like adding your own middleware and so on. It's a little beyond the scope of the question here to go through all the details of the ASP.NET pipeline, OWIN, how the middleware interacts, etc. A quick Google search for how does web api work with owin brings up a ton of documentation, blog articles, and explanations.
The important aspect there, though, is that there are basically two parts - the OWIN part, with its pipeline, and the Web API part, with its "sub pipeline."
Since the OWIN pipeline starts before the Web API pipeline, in order to make the two work together and have a request lifetime for the whole of the OWIN pipeline, you have to use the Autofac middleware to do that initialization. Then that same scope from the OWIN pipeline needs to make it into Web API. That also means when the Web API request is done, the OWIN pipeline needs to be able to handle the disposal of things rather than letting Web API handle it.
Hence the documentation: "Extends the Autofac lifetime scope added from the OWIN pipeline through to the Web API dependency scope." It's taking the scope created at the start of the OWIN pipeline and making sure it's the same scope that goes into the Web API pipeline.
Some applications not only have Web API but also ASP.NET MVC, all of which is trying to be coordinated through that OWIN pipeline and needing everything to work together. All of the stuff Autofac has in place to get Web API, MVC, and OWIN wired up is there for a reason - to make sure it all plays nicely together.
Generally if something is optional, the docs will explicitly say so. For example in the Autofac Web API documentation it's noted that it's optional to register filter and model binder provider handling. In this case, it's not really optional.
I'm following guides/docs on registering HTTP client within my application. There are couple of services I need to call so I decided to go with "Typed clients".
In order to call another service I need to use OAuth - since this is service-to-service call, when I obtain access token, I cache it + I have setup periodical refresh of token. This means there's another component IAccessTokenCache which gives me access token for service.
Thing I'm struggling to figure out is how to register and configure my typed HTTP client providing it also dependency on IAccessTokenCache.
I'm using ASP.NET Core 2.1 (crucial detail, read on).
HTTP client wrapper looks like this (from: HttpClientFactory in ASP.NET Core 2.1 (Part 2) ):
public class ServiceFooClient
{
public ServiceFooClient(HttpClient client)
{
Client = client;
}
public HttpClient Client { get; }
}
And this is how I register and configure client:
services
.AddHttpClient<ServiceFooClient>(
c =>
{
c.BaseAddress = new Uri("https://www.foo.svc");
// TODO: grab particular access token from cache
c.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "...");
})
.AddHttpMessageHandler<ResponseMonitorHandler>()
.ConfigureHttpMessageHandlerBuilder(
b =>
{
var handler =
b.AdditionalHandlers.OfType<ResponseMonitorHandler>().FirstOrDefault();
if (handler != null)
{
handler.ServiceName = "Foo Service";
}
});
... I'm already configuring HTTP client and even adding my custom HTTP handler. You can see exact point where I want to access IAccessTokenCache, but I can't.
Possible solutions I can think of:
Configure underlying HttpClient in ServiceFooClient wrapper, like:
// ctor
public ServiceFooClient(HttpClient httpClient, IAccessTokenCache tokenCache)
{
Client = httpClient;
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenCache.GetToken("Foo"));
}
This could work nicely, except I don't configuration decoupling - suddenly dedicated HTTP client has part of configuration in Startup (base URI, additional HTTP handler) and another part in wrapping class (setting authorization header).
Not using AddHttpClient extension method (and others)
I don't really need to call HttpClientFactoryServiceCollectionExtensions.AddHttpClient<T>(...) - I could do all that stuff myself. But as lazy developer... I don't even want to finish this sentence. There's quite a lot of registering inside, so this is just big no no for me.
Upgrade to ASP.NET Core 2.2
Related to previous point - in 2.1, there's no overload of AddHttpClient (2.2: AddHttpClient<TClient>(this IServiceCollection services, Action<IServiceProvider, HttpClient> configureClient)) which would accept callback with service provider. Upgrading to 2.2 would be probably the best solution, yet I will have to be pretty sure that nothing else gets broken (and I already know that there is/was BC break with getting/setting request tracing ID on HTTP context). This could be potentially risky, so I'm trying first to solve my issue in scope of 2.1.
Compare branch of 2.1 with 2.2: HttpClientFactoryServiceCollectionExtensions
Custom HTTP handler setting request headers
Same way as I now register ResponseMonitorHandler, I could register HTTP handler which has access to IAccessTokenCache and sets request authorization header.
But again, as in first case, this decouples configuration of HTTP client. Also if I had several different access tokens, I would either need to implement several HTTP handlers or do some logic deciding what token from cache to use based on request properties.
Finally, question: is there any other way I didn't consider? Is there easy solution of this in ASP.NET 2.1? (... apart of just copy-pasting method from 2.2 of course)
Apparently, there's another extension method in 2.1 ConfigureHttpClient(IHttpClientBuilder, Action<IServiceProvider,HttpClient>) which does exactly what I need!
Bakground:
I want to develop a multi-tenant application in ASP.NET Core and have been looking into Ben Fosters Saaskit library which seems to provide good solutions for common problems in multitenancy applications.
Problem:
The SaasKit have a UsePerTenant method which is nice for doing different things per-request depending on current tenant.
My goal is to use the UsePerTenant method combined with different IOptions objects injected via dependency injection. This can be used in the authentication middleware like
AddAuthentication().AddCookie(..).AddOpenIdConnect(...)
Which is configured in the ConfigureServices method in Startup.cs
public class Startup
{
// Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
...
}
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app)
{
...
}
}
I can’t make the authentication middleware in ASP.NET 2.0+ use different IOptions objects per-request since the ConfigureServices method in the Startup.cs file only runs once every application startup and the UsePerTenant method should be used in the Configure method which is running for each incoming/outgoing request in the ASP.NET pipeline.
Question:
How to dynamically change cookie and OpenID Connect options in the ConfigureServices method based on current tenant?
I have found a good way to get per tenant options for any type of ASP.NET Core options, including cookie or openID Connect. I have wrapped this up into a framework called Finbuckle.MultiTenant.
It basically boils down to a setup that looks like this:
services.AddMultiTenant().
WithInMemoryStore()).
WithRouteStrategy().
WithPerTenantOptionsConfig<CookieAuthenticationOptions>((o, tenantContext) => o.Cookie.Name += tenantContext.Id);
See my here for more information if you are curious: https://www.finbuckle.com/MultiTenant
The following PR provides a solution for the above question.
https://github.com/saaskit/saaskit/pull/96
The PR have been merged with the "master" branch now.
It wasn't merged yet (November 2018)
We just stood up an on-premise MS Service Fabric cluster. I have some WebAPI's i'd like to host in it. I'm looking for resources on how to take our standard 4.5 WebAPI's and host them in Service Fabric without have to create a Service Fabric project and migrate it; that just seems too complex.
I looked at some of the Service Fabric sample projects, and it seems all the projects are tightly coupled with Service Fabric. My goal is keep these apps unaware of Service Fabric.
Any links of information is greatly appreciated, thanks!
We did this way:
Created the service fabric projects in the same solution of our WebAPI.
Inside the ServiceFabricHost project we created our HttpListenerService to expose the ports using service fabric, the same you would do to a SelfHosted WebApi.
Configure the ServiceFabricHost to open the needed endpoints.
Add the reference to the WebApi project
Use the WebApi Startup to send the IAppBuilder and configure the api with our external(SF) configuration, like ports and URL.
The secret is: when you create a self hosted web api, your generaly create a console application, like the asp.net docs. With service fabric, you replace the console with the ServiceFabricService, that is similar to a ConsoleApplication, but in this case will be a statelessService.
In this case, we used a stateless service for HttpListenerService, if you need a StateFull service, you will need to refactor your Api to use the reliable collections.
The fellow Vaclac, created a nice tutorial for this:
https://azure.microsoft.com/en-us/documentation/articles/service-fabric-reliable-services-communication-webapi/
If it's a standalone web application with a self-hosted web server (e.g., Katana, not IIS), then you can simply run it as a Guest Executable.
If it's not self-hosted and requires a separate web server to run, like IIS, then you can look at running it in a Container.
I had the same problem and solved it by using the DependencyResolver.GetService() method on the HttpConfiguration object in the Startup() class. Create a new Service Fabric Stateless/Statefull WebAPI project. In the Startup() class, add the following code:
public static class Startup
{
// This code configures Web API. The Startup class is specified as a type
// parameter in the WebApp.Start method.
public static void ConfigureApp(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
// Allow custom routes in controller attributes.
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "{controller}/{action}/{id}",
defaults: new { controller = "API", action = "HealthCheck", id = RouteParameter.Optional }
);
//inject controllers here
config.DependencyResolver.GetService(typeof({{YourWebAPIRootNamespace}}.Controllers.APIController));
appBuilder.UseWebApi(config);
}
}
This allows you to deploy your existing APIs into Service Fabric without having to migrate the entire code base to a new project. Don't forget to update the app.config in the new project with all applicable settings from your web.config.
Full blog post here http://thenameisirrelevant.com/hosting-an-existing-webapi-in-service-fabric
well, I am now learning aspnet core , I can't understand when does the application start its server(like IIS or KestrelServer),and how the server listen the httprequest and forwards the request to the application. can anybody help me? thanks
Well, let's start from beginning (As I couldn't figure out your knowledge about C#)
Every C# application must contain a single Main method specifying where program execution is to begin, so there it is, by default the templates have a Class Program where you can set the type of WebServer that you'll use, and tell the server to start listening for HTTP requests, something like:
public static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.AddCommandLine(args)
.Build();
var host = new WebHostBuilder()
.UseKestrel()
.UseConfiguration(config)
.UseStartup<Startup>()
.Build();
host.Run();
}
In AspNetCore and even in AspNet (MVC or WebApi) you can (and should) use OWIN (aka Katana or vNext, that are Microsoft's OWIN implementations for AspNet and AspNetCore respectively).
OWIN represents a Interface (just a specification), that tell how WebServers should comunicate with WebApplications. Normally it handle the Http Requests to a pipeline that you can plug Middlewares, like Authentication/Authorization, Log, Error Handlings and so on, and in the end of the pipeline you should plug your Web Application.
In AspNetCore you set your Middleware Pipeline by using UseStartup<MyStartupClass> in your Host configuration see Main method above and simple as that your Pipeline will handle every HttpRequest.
When building a MVC applications in AspNetCore (.UseMvc()) you are setting a middleware that tells your application to look for classes that inherit from Microsoft.AspNetCore.Mvc.Controller to look for RESTful entry points (HTTP GET, POST...)
This is just a simple overview, and you can learn a lot more looking in the documentation of this technologies. Just search for tags like Katana, vNext, OWIN, OWIN Middleware, OWIN Pipeline...
ASP.NET Core application anatomy is discussed here at this asp.net core introduction.
Some important text that answers your question is as follows from the tutorial:
An ASP.NET Core app is simply a console app that creates a web server in its Main method. Main uses WebHostBuilder, which follows the builder pattern, to create a web application host. The builder has methods that define the web server (for example UseKestrel) and the startup class (UseStartup). In the example above, the Kestrel web server is used, but other web servers can be specified. The Startup class is where you define the request handling pipeline and where any services needed by the app are configured. The Startup class must be public and contain the following methods:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
}
public void Configure(IApplicationBuilder app)
{
}
}
I guess this will help you to understand how asp.net core handles Http requests.
Thanks