I want to enable making several concurrent requests to server from a single client. How can this be done with .Net WebApi? In ASP.Net MVC 3 it could be enabled with adding the follow attribute to the controller:
[SessionState(SessionStateBehavior.ReadOnly)]
public class SomeController : AsyncController
{
//.....
}
Information about MVC Session was found here:
The Downsides of ASP.NET Session State
But in Web Api application it doesn't work. I've also accessing session data like in this question:
Accessing Session Using ASP.NET Web API
So, I think thats why I can't make multiple requests at once from client. What should I do enable that feature?
Resolved by adding:
void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
{
HttpContext.Current.SetSessionStateBehavior(
SessionStateBehavior.ReadOnly);
}
and
public override void Init()
{
PostAuthenticateRequest += MvcApplication_PostAuthenticateRequest;
base.Init();
}
to Global.asax
Yes, there are a lot of problems with using session in your ASP.NET applications. Moreover, by default, HTTP (and by extension, REST- like/style application) is stateless – and as a result each HTTP request should carry enough information by itself for its recipient to process it to be in complete harmony with the stateless nature of HTTP.
Web Api was not design to support Asp.net Session ; you have nothing else to do.
So, If you need some information in a Web Api, do not rely on Seesion State but add them into your request
What is very funny, is that some people want to support Session in Web Api ...
Related
We have MVC Web Application with AnjularJS integrated (legacy product) and deployed as a Web Application. We expose ApiControllers for Ajax calls from the AngularJS script .We have multiple instances of this application running behind a load balancer. We recently integrated Azure AD for authentication and use OpenIDConnect flow. User login succeeds but subsequent requests (Ajax calls) to the ApiControllers fail randomly with 'Unauthorized' error.
OpenIDCOnnect Authentication setup
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = "XXXXX",
Authority = "https://login.microsoftonline.com/xxxx.onmicrosoft.com",
PostLogoutRedirectUri = #"https://localhost:44360/",
});
}
Then each MVC and API controller is annotated with Authorize attribute
[Authorize]
public class HomeController : Controller
Our Analysis
We suspect this issue might be because of the application running multiple instances and during login the session would be established with that particular instance. Subsequent requests are going to other instances randomly and the instance does not have the session information. When we deploy only one instance of the application, this error is not seen.
Questions
When I read online about Azure AD, the recommended way for Ajax calls is to use ADAL.js implicit flow. Since ours is not a purely single page application, I am not sure if this would be a valid choice. We want to see if we can solve this by sticking to OpenIDConnect.
Is there a way to store this session information in a distributed store so that multiple instances of the application can share it? I see interface IAuthenticationSessionStore in CookieAuthenticationOptions which can be used but not finding enough information on its purpose.
If this is a JS app using the MVC app to service API/AJAX requests then the MVC app should not use cookies at all. It should just validate the id_token passed from the JS client in the Authorization header. Your app is failing probably because you are trying to use cookies, encrypting them on one server and then trying to use them on another. Have a look here: https://learn.microsoft.com/en-us/azure/active-directory/develop/sample-v1-code#single-page-applications, particularly the source code for the Startup.Auth.cs class: https://github.com/Azure-Samples/active-directory-angularjs-singlepageapp/blob/master/TodoSPA/App_Start/Startup.Auth.cs.
If you are mixing SPA (JS) paradigm with serving regular HTML then you have will have to figure out how to use both cookies and tokens. Tricky and insecure.
I am using OpenId connect protocol for setting up the AzureAD authentication for ASP.NET MVC5 application. It is working fine as expected. The same code base has WEB API 2 controllers which is used by another angular app. The WEB API endpoints are setup with allow anonymous access in the root web.config file which is common for both ASP.NET MVC5 app and the WEB API 2 controllers.
There is a Startup.cs page which contains the logic for the OpenID connect protocol implementation.
Startup.cs:
[assembly: OwinStartup(typeof(MyApp.CMS.Web.Startup))]
namespace MyApp.CMS.Web
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
ConfigureAuth(app);
}
}
}
The namespace for the WEB API 2 Controllers is MyApp.CMS.Web.Controllers.ApiControllers
Here I want to stop execution of all the calls that are made to Startup.cs whenever any WEB API endpoint is invoked.
Can anyone help me to provide their guidance to fix this issue.
The WEB API endpoints are setup with allow anonymous access in the root web.config file
Actually, no - that is not possible.
Both MVC and Web API use HTTP modules as endpoints (that end up calling controller action methods). The ASP.NET web.config settings only apply to physical files and folders on the web server. MVC and Web API bypass these web.config settings so they have no effect.
Here I want to stop execution of all the calls that are made to Startup.cs whenever any WEB API endpoint is invoked.
The code in Startup.cs is only executed one time per application start (or app pool refresh), so the only thing that takes place here are application-wide settings. It doesn't take part in the per-request authorization of controller actions.
If you want to control access to Web API controller action methods, you should use [Authorize] attribute from the System.Web.Http namespace (or a customized subclass of it). You will also need to setup Authorization with Web API for [Authorize] attribute to function.
To apply authorization to the entire Web API, you can register System.Web.Http.AuthorizeAttribute as a global filter.
GlobalConfiguration.Configuration.Filters.Add(new System.Web.Http.AuthorizeAttribute());
MVC has its own [Authorze] attribute and completely ignores the one from Web API, so this setting will have no effect on MVC.
I understand what OWIN is, and it is good, and generally that Katana is a Microsoft implementation the standard in terms of the ASP.NET ecosystem.
I've also read that Katana has only so far been designed to work with WebApi and SignalR, since these take no dependency System.Web. Cool.
However, a new ASP.NET MVC 5 project template does include some Katana stuff and references Microsoft.Owin.Host.SystemWeb and that's where I get confused.
"[SystemWeb] provides an OWIN server that runs in the ASP.NET request pipeline"
http://www.asp.net/aspnet/overview/owin-and-katana/an-overview-of-project-katana
So, on IIS, does a request off the wire flow through the Owin pipeline before being routed to a WebApi action? And MVC actions, too? At what point in the pipeline does Owin sit?
Look at the following code from ChallengeResult.cs the template:
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
Request.GetOwinContext().Authentication.Challenge(LoginProvider);
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
response.RequestMessage = Request;
return Task.FromResult(response);
}
This appears to be talking to two pipelines; it tells the authentication middleware on the Owin pipeline to send a 401 challenge and then also returns a 401 via the normal response messaging system.
I'm sure its simple, but I'm confused.
When you use Owin.Host.SystemWeb, you are injecting in the usual HttpModules pipeline an HttpModule meant to host the OWIN pipeline.
From the IIS/ASP.NET perspective, the OWIN pipeline will be executed in that context.
If you want to exercise finer control on what runs when, you can add specific stage markers that map to the traditional event sequence.
I recommend Prabu's article at:
http://www.asp.net/aspnet/overview/owin-and-katana/owin-middleware-in-the-iis-integrated-pipeline
It gives a very nice overview of the process.
as you know MVC and web api action filters uses different namespaces for their filters:
in web api:
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
HttpActionExecutedContext is in system.web.http.filters
in MVC:
public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
ActionExecutedContext is in system.web.mvc
I want to have one filters for all of my controllers whenever web api or MVC.
so how can I solve this issue?
MVC and Web API are different frameworks and where they converge is the hosting part. At this point in time, MVC and Web API can be web-hosted (IIS + ASP.NET pipeline) and hence you can write an IIS module to do what you want.
OWIN middleware could be a better option but unfortunately MVC cannot be OWIN-hosted at this point. However, you can use a stage marker to run an OWIN middleware in ASP.NET pipeline at the stage you want but as far as I can see, PipelineStage enum has PreHandlerExecute as the last stage. This means you can do something like OnActionExecuting but not OnActionExecuted.
After getting an advice about using ServiceStack for my asp.net MVC website
(Maintaining state in Asp.Net MVC website), I started implementing it in my project - but some stuff is still unclear for me.
Currently I have two projects: one is the asp.net MVC project and the other is the BL project (a class library that holds all the business logic).
All controllers in the MVC project make calls to classes/functions in the BL project.
For now, the mvc project loads the BL's DLL, but in the future when the website will grow, the BL's project will run on separate machines.
I would like to use ServiceStack for session management/caching and authentication (which both of them usually depended on each other).
My questions:
1) Is it possible to use only these two features without the functionality of message based web service? ServiceStack need to be initialized, and it throws me an error when initialized twice (in both projects).
2) Is it possible to split the implementation of ServiceStack between the two projects? I would like to maintain the process of authentication in the BL project using the ServiceStack's authentication providers, but handle all the UI/cookies by myself (or with the help of ServiceStack) in the mvc project.
3) I would like to use ServiceStack's caching in the BL project, but I guess that I still need to maintain some session cookies to receive the session id. What is the right way to do it? Are there any built-in helper functions for this purpose?
Thanks in advance!
1) Is it possible to use only these two features without the functionality of message based web service? ServiceStack need to be initialized, and it throws me an error when initialized twice (in both projects).
If you install the latest ServiceStack.Mvc NuGet package you will get the base ServiceStackController which is an MVC Controller providing convenient access to ServiceStack's built-in providers. Although you still need to auto-wire your controllers with the dependencies it needs, e.g. an injected ICacheClient.
Although even if you're not using ServiceStack's WebFramework, having an AppHost is a convenient place to register your dependencies. ServiceStack is triggered by ASP.NET's IHttpHandler mappings specified in the Web.config, so if you don't have any mappings specified ServiceStack is never able to be called externally, but the registered dependencies are still able to be accessed internally with:
var cache = AppHost.Resolve<ICacheClient>(); //Get ICacheClient for SS IOC
2) Is it possible to split the implementation of ServiceStack between the two projects?
If you do have an AppHost, you cannot have more than one instance in a host project (by design) since an AppHost should be analogous to a host project where all your service dependencies should be registered and settings configured that apply to your entire web application or service.
You can however split the implementation of your services across multiple assemblies and have ServiceStack scan them all by specifying them in your AppHostBase constructor, e.g:
public class AppHost : AppHostBase
{
public AppHost() : base("My Service",
typeof(AServiceInDll1).Assembly, typeof(AServiceInDll2).Assembly/*, etc.*/){}
}
2) cont. I would like to maintain the process of authentication in the BL project using the ServiceStack's authentication providers, but handle all the UI/cookies by myself (or with the help of ServiceStack) in the mvc project.
Look at the ServiceStack.UseCases CustomAuthenticationMvc example project for an example of using MVC but authenticating with ServiceStack.
3) I would like to use ServiceStack's caching in the BL project, but I guess that I still need to maintain some session cookies to receive the session id. What is the right way to do it? Are there any built-in helper functions for this purpose?
You can use any of ServiceStack's Caching providers just like any other C# class, i.e. have your Business Logic binded to ICacheClient and inject the concrete implementation in your IOC.
For sessions you can use the base.SessionAs<T> method in the ServiceStack.Mvc ServiceStackController to access the session. To Save back the session you can use the IHttpRequest.SaveSession() extension methods. Although both these methods require the ASP.NET context (it uses ASP.NET's HttpContext singleton if not provided) to work since it relies on ServiceStack's ss-id/ss-pid cookies that are automatically instructed to be added on the client (by the server) whenever you access the Session.
If you don't want your business logic services to have a dependency on ASP.NET's System.Web I recommend accessing and saving the session to be done in your controllers and passed to your business logic.
I recommend reading the Sessions Wiki Page for more background info on how ServiceStack's sessions work.
Integration of ASP.NET Context between ServiceStack and ASP.NET or MVC
I'll add this info since it's useful for anyone doing advanced integration between ServiceStack and ASP.NET or MVC as some of ServiceStack's extension methods rely on these built-in types.
You can create a ServiceStack IHttpRequest or IHttpResponse (within any HTTP/Controller request) with:
var ssHttpRequest = System.Web.HttpContext.Current.Request.ToRequest();
var ssHttpResponse = System.Web.HttpContext.Current.Response.ToResponse();
Finally you can create a complete request context (that encapsulates both a IHttpRequest and IHttpResponse) with:
var ssRequestContext = System.Web.HttpContext.Current.ToRequestContext();
Not sure I fully grasp your questions and how you would like to split the projects across multiple servers. I'll try my best to answer your questions...
Is it possible to use only these two features without the functionality of message based web service? ServiceStack need to be initialized, and it throws me an error when initialized twice
It seems like you're trying to run 2 instances of ServiceStack (maybe even 2 websites) within one solution (one in your web project and once in your BL layer). I don't think that's possible. Your BL layer can share ServiceStack libraries and you can configure (within AppHost.Configure method) those in your web project that references your BL project.
Is it possible to split the implementation of ServiceStack between the two projects?
I think the answer is yes, but you would have have one instance of ServiceStack used by both the projects. This would share the Session state across the projects. There might be a way to have two projects with there own instances of ServiceStack...see https://github.com/ServiceStack/ServiceStack/wiki/Self-hosting.
I would like to use ServiceStack's caching in the BL project, but I guess that I still need to maintain some session cookies to receive the session id.
If ServiceStack is being used across both projects you can access all session data in UserSession (https://github.com/ServiceStack/ServiceStack/wiki/Sessions). If you MVC Controllers inherit from ServiceStackController you can use SessionFeature.GetSessionId() to get the session Id. In your ServiceStack Service (classes that implement Service) you can get the session data from using base.Session.
Hope this helps.