Is it possible to access HttpContext.Current.Session through a WebAPI ? can we make it inheriting IRequiresSession?
I have a generic handler doing a Session set after an API call which I want to remove.
public void AccountController : ApiController, IRequiresSessionState
{
public void Login()
{
setsession(){}
}
}
Technically, yes, although I'd really advise against this practice - a REST API should be completely stateless (cookies and other client-side state is OK).
If you absolutely must do this, you can grab the HTTP context like so:
var context = Request.Properties["MS_HttpContext"] as HttpContext;
At which point you just use its Session property to get the session.
Note that this breaks certain contracts assumed by System.Net.Http - specifically it means your API controllers can never be self-hosted because they're coupled to ASP.NET. If you're OK with this, and with the fact that your API controllers may not work properly from a web farm unless you re-architect everything to use distributed sessions - well then, go for it.
P.S. It is also possible to use IRequiresSessionState, but you can't use it on the controller itself, you need to use it on an HttpControllerHandler and set it as the RouteHandler. The approach is discussed in this MSDN thread. Again, I can't recommend strongly enough against this idea, it violates the basic principle of a Web API - but, if you've got a really good reason for it, then it's another option which is a bit more reusable.
Casting it as HttpContext did not work for me using Web Api 2.1. However I could use HttpContextWrapper.
var context = Request.Properties["MS_HttpContext"] as HttpContextWrapper;
Yes - although not recommended. Here's a working answer based on the answers above (for WebAPI version 2.x)
var context =(HttpContextWrapper)Request.Properties["MS_HttpContext"];
var sessionId = context.Request.Params["ASP.NET_SessionId"];
Related
I've read a lot of answers saying to just use the built-in Nancy Session/User object, but this isn't an option in my case.
Using WCF I was able to access the ASP.Net Session["SomethingStuffedIntoSessionFromAWebForm"] by enabling aspNetCompatibilityEnabled in the web.config (other stuff had to been done too, probably), but I can't seem to figure out how to get a handle on the System.Web.HttpContext.Current.Session (or anything else in the current context) from within a Nancy module.
My 1st thought was to inject it in the bootstrapper but I can't even get a handle on the System.Web.HttpContext.Current.Session there either. Any ideas?
Edit
I ended up just stuffing an encrypted version of my desired session object into a cookie upstream and checking/validating against it in the module's BeforePipeline... not too crazy about this approach, but it suits my needs for now.
As far as I can tell, when a Nancy module handles a request, it bypasses the Asp.Net pipeline, so while I actually do have access to HttpContext.Current, Session is not populated.
Inherit IRequiresSessionState to enable Asp.net Session.
public class NancyAspHttpRequestHandler
: NancyHttpRequestHandler, IRequiresSessionState
{
}
and use NancyAspHttpRequestHandler in handler registration, this can be possible using Nancy.AspNet hosting.
This will solve the problem
I have been asked to change a legacy .asmx web service and there are a few issues I would appreciate some guidance on.
The web methods are decorated like this:
[WebMethod(EnableSession = true), ScriptMethod(ResponseFormat = ResponseFormat.Json)]
In my particular method, I am returning data from a database, which I return as a list of to of objects using JSON.
I noticed that the JSON is still returned without the: ScriptMethod(ResponseFormat = ResponseFormat.Json part.
In that case:
can I safely remove this from here?
if it still works, does that mean it will be configured elsewhere in a base class or config file perhaps?
What is the purpose of the (EnableSession = true) and is it required if the service does not update the data and the read data is rarely changed?
Sorry for the basic rather vague questions but I've not worked with .asmx web services before. Can someone point me in the right direction please?
Thanks
EnableSession = true allows you to access the Session collection, which is part of the HttpContext.Current.Session. If the code in your web method does not use the Session collection, then yes it is safe to remove, but if it does use the Session collection, then removing this attribute will cause your web service logic to throw an exception, because it will not have access to the Session collection.
ScriptMethod(ResponseFormat = ResponseFormat.Json) is explicitly defining that this web method will return JSON, but since JSON is the default return type, then removing it does not matter. So the short answer is, yes it is fine to remove this, but it will not hurt to leave it there (in fact I would argue that is better to because it explicitly states this thing is returning JSON data).
AS #Karl already said if you need to access Session in webmethod, you've to decorate your method with the said attribute.
Now I've seen people complaining about webmethod not returning JSON response on SO and Asp.net official forum even though they have decorated their method with
ScriptMethod(ResponseFormat = ResponseFormat.Json)
because they might have missing configuration in web.config.
I would suggest you to go through Dave Ward's below articles that may help you to understand what needs to be done to return JSON response with ASMX:
ASMX and JSON – Common mistakes and misconceptions
ASMX ScriptService mistake: Installation and configuration
I'm looking for some guidance on how to implement authorization security for SignalR on a back end service running in a self-hosted (non-IIS) environment, that is called from a Web application. The backend app is basically a monitor that fires SignalR events back to the HTML based client. This all works fine (amazingly well actually).
However, we need to restrict access to the server for authenticated users from the Web site. So basically if a user is authenticated on the Web site, we need to somehow pick up the crendentials (user name is enough) and validation state in the backend app to decide whether to allow the connection as to avoid unauthorized access.
Can anybody point at some strategies or patterns on how to accomplish this sort of auth forwarding?
I am having similar issues here, as in my web app I use a simple cookie authentication system which uses an AoP style approach to check for any controllers with an attribute, then will get the current context (be it from the static HttpContext.Current or from the target invocation object depending on the type of interceptor) and then verify the cookie exists, it contains right data, then finally verify the token with the db or cache etc.
Anyway this approach can also be used for Signalr, although its a bit more long winded and you are using dependency injection. You would basically wrap the hub calls with the desired attribute, then set up your DI/IoC configuration to intercept these calls, then either get the hub instance within your interceptor and get the cookie (or your custom authentication mechanism) from the request, verify it is all valid or not, and if not then throw a new HttpException("403", "Not authenticated"); which should kick the user out and return back before it even hits your hub method, this way you can put the logic in one place (your interceptor, or a class the interceptor consumes) then just wrap any method that needs to use this authentication using your attribute.
I use Ninject and the interception extension, but most major DI frameworks these days have some form of IoC plugin/extensions, such as Autofac, Windsor, Spring etc.
If you were not happy going down the route of introducing DI and/or AOP to your current project, then maybe you could just create a custom hub instance which contains your authentication logic and then just use that in your hubs, so ok you will still be manually calling some authentication logic from within each hub method you want to protect, but its less code, so something like:
public class AuthorisableHub : Hub
{
private ISomeAuthenticationToken GetSomeAuthenticationTokenFromRequest(Request request) // probably a SignalR specific request object
{
// Get your token from the querystring or cookie etc
}
private bool IsAuthenticationTokenValid(ISomeAuthenticationToken token)
{
// Perform some validation, be it simple or db based and return result
}
protected void PerformUserAuthentication()
{
var token = GetSomeAuthenticationTokenFromRequest(Context.Request);
var isRequestValid = IsAuthenticationTokenValid(token);
if(!isRequestValid)
{ throw new HttpException(403, "<Some forbidden message here>"); }
}
}
public class MyFancyPantsHub : AuthorisableHub
{
public void TellAllClientsSomethingSecret(ISecret secret)
{
PerformUserAuthentication();
// Do stuff with the secret as it should have bombed the user out
// before it reaches here if working correctly
}
}
It is not perfect but would work (I think), also I am sure I once read somewhere that Hubs are newly instantiated for each request, and if this is indeed true, you could possibly just put this logic in your constructor if you want to apply the authentication to every action within the hub.
Hope that helps, or gives you ideas... would be interested in knowing how you did solve it in the end.
SignalR does not provide any additional features for authentication. Instead, it is designed to work with the authentication mechanism of your application.
Hubs
You should do authentication as you normally would and then use the Authorize attribute provided by SignalR to enforce the results of the authentication on the Hubs.
The Authorize attribute can be applied to an entire Hub or particular methods in the Hub. Some examples:
[Authorize] – only authenticated users
[Authorize(Roles = "Admin,Manager")] – only authenticated users in the specified .NET roles
[Authorize(Users = "user1,user2")] – only authenticated users with the specified user names
You can also require all Hubs to require authentication by adding the following method in the Application_Start method:
GlobalHost.HubPipeline.RequireAuthentication();
Persistent Connections
You can use the user object in the request to see if the user is authenticated:
request.User.IsAuthenticated
At my workplace we are in the process of upgrading our Time and Attendance setup. Currently, we have physical terminals that employees use to check in and check out. These terminal communicate to a 3rd party T&A system via web service calls.
About the T&A web service:
Hosted on IIS 6
Communication is with WCF over HTTP
We're only interested in one of the exposed methods (let's call it Beep())
What I need to do:
Leave the original T&A system in place, untouched
Write a custom service that also reacts to calls to Beep()
So, essentially, I need to piggy-back on all the calls to Beep(), but I'm not sure what the best approach is.
What has been considered already:
Write a custom webservice that implements the exact same same contract as the T&A service and direct all the terminals to that custom service. The idea being that I can then invoke the original T&A service from my custom service, as well as applying any other logic required.
This seems overly invasive to me, and seems needlessly risky. We want to leave the original system as unmodified as possible.
Write a custom HTTP Handler to intercept calls to the original T&A service.
We've actually already done something like this in house, but our implementation takes the original HttpRequest, extracts the contents, invokes a custom service, and finally create a new HttpRequest based on the original request so that the original web service call to Beep() is made.
What I don't like about this approach is that the original HttpRequest is lost. Yes, a second, supposedly identical, request is created, but I don't know enough about HttpRequests to guarantee this is safe.
I prefer option 2, but it's still not perfect. Ideally we wouldn't need to destroy the original HttpRequest. Does anyone know if this is possible?
If not, can anyone suggest another way of doing this? Can IIS be configured to fork requests to two destinations?
Thanks
UPDATE #1
I have found a solution (documented here), but I'm still open to other options.
UPDATE #2
I like flup's solution (and justification). He gets the bounty :) Thanks flup!
You can configure the web service to use a custom operation invoker, an IOperationInvoker.
WCF deserializes the original HTTP request as always, but instead of calling Beep() on the existing web service class, it will call your invoker instead. The invoker does its special thing, and then calls Beep() on the original service.
Advantage over implementing an IHTTPModule would be that all things HTTP are still handled by the original web service's configuration, unchanged. You fork off at a higher level of abstraction, namely on the web service's interface, at the Beep() method.
The nitty gritty of setting up a custom operation invoker without changing the existing service class (which makes it harder):
Implement a custom IOperationBehavior which sets the custom IOperationInvoker on the service's Beep() method in its ApplyDispatchBehavior method.
Implement a custom IEndpointBehavior which sets the custom IOperationBehavior in its ApplyDispatchBehavior method.
Put these two behaviors, with your IOperationInvoker, in a class library and add it to the existing service
Then configure the service to use the IEndpointBehavior.
See When and where to set a custom IOperationInvoker? and http://blogs.msdn.com/b/carlosfigueira/archive/2011/05/17/wcf-extensibility-ioperationinvoker.aspx for the invoker bit.
See Custom Endpoint Behavior using Standard webHttpEndpoint on how to configure a custom endpoint.
Sounds actually like you want to integrate your system into an ESB pattern. Now the MS solution to the ESB problem is Biztalk. Biztalk is the thermonuclear warhead nut cracker in this case. You don't want Biztalk.
Check out the results here for lightweight alternatives
I have found a solution using a custom IHttpModule. See sample below:
using System;
using System.Text;
using System.Web;
namespace ForkHandles
{
public class ForkHandler : IHttpModule
{
public void Init(HttpApplication application)
{
application.BeginRequest += new EventHandler(application_BeginRequest);
}
void application_BeginRequest(object sender, EventArgs e)
{
var request = ((HttpApplication)sender).Request;
var bytes = new byte[request.InputStream.Length];
request.InputStream.Read(bytes, 0, bytes.Length);
request.InputStream.Position = 0;
var requestContent = Encoding.ASCII.GetString(bytes);
// vvv
// Apply my custom logic here, using the requestContent as input.
// ^^^
}
public void Dispose()
{
}
}
}
This will allow me to inspect the contents of a webservice request and react to it accordingly.
I'm open to other solutions that may be less invasive as this one will require changing the deployed 3rd party web service's configuration.
If you want to intercept the message to the T&A WCF service i would suggest using custom listener which can be plugged into the service call by making changes in the web.cofig.
This will be transparent.
Please look for WCF Extensibility – Message Inspectors.
system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="ServiceModelMessageLoggingListener">
<filter type=""/>
</add>
</listeners>
</source>
</sources>
</system.diagnostics>
In my asp.net mvc 2 app, I'm wondering about the best way to implement this:
For every incoming request I need to perform custom authorization before allowing the file to be served. (This is based on headers and contents of the querystring. If you're familiar with how Amazon S3 does rest authentication - exactly that).
I'd like to do this in the most perfomant way possible, which probably means as light a touch as possible, with IIS doing as much of the actual work as possible.
The service will need to handle GET requests, as well as writing new files coming in via POST/PUT requests.
The requests are for an abitrary file, so it could be:
GET http://storage.foo.com/bla/egg/foo18/something.bin
POST http://storage.foo.com/else.txt
Right now I've half implemented it using an IHttpHandler which handles all routes (with routes.RouteExistingFiles = true), but not sure if that's the best, or if I should be hooking into the lifecycle somewhere else?
I'm also interested in supporting partial downloads with the Range header. Using
response.TransmitFile(finalPath);
as I am now means I'll have to do that manually, which seems a bit lowlevel?
Many thanks for any pointers.
(IIS7)
I think having a custom handler in the middle that takes care of this is exactly how you should be doing it.
TransmitFile is the lightest-weight programmatic way to serve a file that I am aware of.
However, you might not need to write your own HttpHandler. You can use the MVC handler and just dedicate a controller action to the job. Something like:
http://storage.foo.com/Files/Download/SomeFileIdentifier
...routing to...
public FilesController
{
public ActionResult Download(string id)
{
//...some logic to authenticate and to get the local file path
return File(theLocalFilePath, mimeType);
}
}
The File() method of controller uses TransmitFile in the background, I believe.
(PS, If you want shorter URLs, do it via custom routes in global.asax.)