I am trying to access the Session in Controllers which are part of a webform project. All the session variables are set on ASPX pages
Session["SESSION_KEY_UI_CULTURE"] = ddlLanguage.SelectedValue;
Now on API request from client i need to read Session Variables and perform a task but Session is always null.
[RoutePrefix("api/accounts")]
public class AccountsController : ApiController
{
[Route("config")]
[HttpGet]
public IHttpActionResult GetCompanyConfig()
{
if(HttpContext.Current.Session != null)
{
//Session is always NULL
}
return Ok();
}
}
I have tried removing and adding SessionStateModule in WebConfig file
<remove name="Session" />
<add name="Session" type="System.Web.SessionState.SessionStateModule"/>
ASP.NET Web Api is meant for REST Services which are by definition stateless. Adding the Session back into Web Api defeats the purpose of having a RESTful API.
You may want to reconsider what you're trying to achieve and find another way to solve your Problem.
But there is a way to do what you want:
To activate Session nontheless add the following to your Global.asax
C#
protected void Application_PostAuthorizeRequest() {
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
}
VB
Sub Application_PostAuthorizeRequest()
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required)
End Sub
Here and here are 2 Topics that are going into the same direction which you might want to look at for further information
Related
I started with a WebForms .NET 4.51 application. I then added WebAPI to the same application. In Session_Start() I create a variable instance that I store within the session as follows:
public class Global : HttpApplication
{
protected void Session_Start(object aSender, EventArgs aEventArgs)
{
//Create an object to hold all the settings for the user in the session. This is only loaded once we
//have a user successfully logged in
HttpContext.Current.Session[SYSTEM_SETTINGS_SESSION_KEY] = new SystemSettings();
}
}
and I have a simple property accessor as follows:
public class Global : HttpApplication
{
public static SystemSettings SystemSettings
{
get
{
if (HttpContext.Current == null)
return null;
return HttpContext.Current.Session[SYSTEM_SETTINGS_SESSION_KEY] as SystemSettings;
}
}
}
The above all works well when I am accessing the property from code except when I attempt to do this from within a WebAPI controller as follows via the property from above viz Global.SystemSettings:
public class EmailActivitiesController : ApiController
{
emailBody = EmailToClientsTemplateBuilderHelper.TemplateContentBuild(emailBody, Global.SystemSettings);
}
When I inspect HttpContext.Current.Session it is NULL.
So why is the Session collection null when accessed from the WebAPI controller?
I need to store use the information related to the user's session in the WebAPI controller, so do I need to store things differently now?
UPDATE
The accepted solution also worked for WebAPI 1 which is what the application is using.
This is because WebApi does not have Session enabled by default. WebApi is trying to encourage you to move towards stateless HTTP and RESTful APIs.
I strongly urge you to rework your design without sessions.
With this said, you can enable Session in WebApi 2 by adding this to Global.asax
protected void Application_PostAuthorizeRequest()
{
System.Web.HttpContext.Current.SetSessionStateBehavior(
System.Web.SessionState.SessionStateBehavior.Required);
}
My Question Is This
What configuration step have I missed to make Mvc Surface Controllers work in Umbraco?
My theory is that since there is a folder in the default Umbraco install called /umbraco/ which is used to connect to the CMS that the physical path is interfiering with the route /umbraco/surface/{Controller}/{Action} thus resulting in the ASP.NET YSOD (and an IIS 404
when I try to access a controller on that route that isn't defined.)
Background Information
I have added this class to my App_Code folder in a freshly downloaded copy of Umbraco 6.1.6:
public class MembersController : SurfaceController
{
public ActionResult Index()
{
return Content("Hello, Member!");
}
}
When I navigate to what I think should be the route for my Index() method, I get a YSOD that says the resource could not be found:
the code is not executed and the above error is displayed; however, if I change the Uri to garbage I get an IIS 404 error:
I started getting this in an existing site, thinking my site was screwed up I tried it in a new copy of Umbraco 6.1.6 and got the exact same results.
For the record, I have also tried MembersSurfaceController and its associated Uri, which has the exact same result as above. YSOD when I hit the valid route, and IIS 404 when I don't.
I have changed my umbracoSettings.config to MVC in the /config/ directory as well.
update
I'm using the out-of-the-box web.config file, which has this:
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true">
<remove name="UrlRewriteModule" />
<add name="UrlRewriteModule" type="UrlRewritingNet.Web.UrlRewriteModule, UrlRewritingNet.UrlRewriter" />
.
..
...
On my default Umbraco site I don't have any rewrite rules defined; but on my actual site I have several rewrite rules in place. I'm thinking that's not causing it since I'm seeing the same behavior on both sites though...
I have tried removing UrlRewrite completely I get the same results.
The following approach works for me in Umbraco 7.1, and I expect it to work in 6.1 as well:
Create folder called 'Controllers' within your App_Code folder, and put your surface controllers in there (so that they will be within the 'Controllers' namespace).
E.g. I have the following controller in the App_Code\Controllers folder (and hence, within the 'Controllers' namespace):
namespace Controllers
{
public class ServiceCentersController : SurfaceController
{
public ActionResult GetServiceCenters(string country = "", string region = "", string city = "")
{
...
}
}
}
My site runs on localhost, so I can invoke the GetServiceCenters action by navigating to:
http://localhost/umbraco/Surface/ServiceCenters/GetServiceCenters?country=aa®ion=bb&city=cc
You need a namespace for your controller - the code posted above doesn't have any namespace:
public class MembersController : SurfaceController
{
public ActionResult Index()
{
return Content("Hello, Member!");
}
}
That is why making a namespace of Controllers works ... but you could make this any logically named namespace you want.
I am hosting a wcf service in IIS 7. I was curious if it would be possible to create my own .svc HttpHandler mapping and class to handle service requests.
For example, if I was to intercept any requests to files that ended with an extension of ".foo" I could add this to my web.config
<handlers>
<add name="*.foo_**" path="*.foo" verb="*" type="MyServer.FooHttpHandler" />
</handlers>
And I could have a class in my default root that did the following
public class FooHandler: IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// do stuff, validate?
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.AddHeader("Content-Disposition", string.Format("filename={0}", url));
HttpContext.Current.Response.AddHeader("Content-Type", "fooMimeType");
HttpContext.Current.Response.WriteFile(url);
HttpContext.Current.Response.End();
}
public bool IsReusable
{
get { return false; }
}
}
Is it possible to do something like this with wcf .svc requests? I'm not sure if it'd be the exact same thing or not, since I'm not necessary serving a file to respond with, I want to intercept and proxy the response.
Or is a better way to implement a service behavior that does my required pre-service logic?
What are you trying to achieve? Not sure if you can replace the existing *.svc http handler - but what you can do much more easily is create your own custom ServiceHostFactory for the WCF service. You basically add one attribute your *.svc file:
<%# ServiceHost Language="C#" Debug="true"
Service="YourNamespace.YourService"
Factory="YourNamespace2.YourServiceHostFactory" %>
Using this, IIS will now instantiate your own YourServiceHostFactory and ask you to create an instance of the YourService class. Maybe you can hook into the flow here and do what you need to do?
You could use ASP.NET Routing and an IRouteHandler that returns your own IHttpHandler implementation as well if you really want to as well
http://msdn.microsoft.com/en-us/library/system.web.routing.iroutehandler.gethttphandler.aspx
http://msdn.microsoft.com/en-us/library/cc668201.aspx
I've done this in the past when setting up WCF Data Services and I don't see why it can't work here as well.
I need to redirect a user to a different page if they visit a certain set of pages in a web. There is one condition: I'm not allowed to touch the IIS. I have googled around and found a thing called the custom HttpHandler for WSS 3.0. It sounded like something that I can use to capture the URL the user enters (the most malicious way to get to a page that should really be redirected) and redirect them to another page/web. But having not have the chance to use it yet, I was wondering am I on the right track by using a Custom HttpHandler to redirect a user to a different page in Sharepoint using C#?
Many thanks.
HttpHandlers are used by IIS to "handle" different document types, for instance you have separate .asmx handle, .aspx handler, .ascx handler, etc.
Look into SPUtility.Redirect
You can use the SPUtility.Redirect method whenever you want to direct the user to a different page. For example, you might create a landing page that determines the user's role membership, and based on that information you can redirect them to an appropriate page. Or, based on the contents of a query string issued by the user's browser, you might redirect them to a page that can process the query string, such as the Search Center results page.
Alternatively, you can look into Using Disposable Windows SharePoint Services Objects.
--EDIT--
This is in response to your comment; you are thinking in the right direction
Create a custom HttpHandler; Example 1, Example 2
Whenever a user requests a url, your custom HttpHandler is going to process that.
Redirect() if you like the url, else otherwise.
But for your Custom HttpHandler to work, it should be called first - so in your config file you will have to provide the value in path. Usually an extension is added here. But you can replace that with a * to work for all request. I believe that would work.
<httpHandlers>
<add verb="*" path="*.aspx" type="MyNameSpace.MyHttpHandler, MyAssemblyName" />
</httpHandlers>
--EDIT--
This is in response to your comment. Assuming that you have "access" to pages so that you can write javascript in it, you can use the javascript in following way.
<script language=JavaScript>
function RedirectIfUnAuthorized()
{
//Get the location of the current page.
var currentUrl = new String( document.location.href )
//See if it belongs to the urls you are looking for; redirect if so.
if (currentUrl == "http://www.thisUrl.com/page1.aspx") {Response.Redirect("http://www.GOOGLE.com")}
if (currentUrl == "http://www.thisUrl.com/page2.aspx") {Response.Redirect("http://www.BING.com")}
if (currentUrl == "http://www.thisUrl.com/page3.aspx") {Response.Redirect("http://www.someother.com")}
}
</script>
You may call the above javascript in the page's OnLoad event.
Are you allowed to deploy code on the server? Or is that touching IIS too?
(SharePoint makes changes to web.config too. If you're allowed to deploy code, so could you. If you don't tell your admins they probably wouldnt even notice.)
You can 'deploy' your web.config changes through an SPWebConfigModification and deploy any web.config redirections or httphandlers that way.
HTTP handlers are the end point
objects in ASP.NET pipeline and an
HTTP Handler essentially processes the
request and produces the response. For
example an ASP.NET Page is an HTTP
Handler.
HTTP Modules are objects which also
participate the pipeline but they work
before and after the HTTP Handler does
its job, and produce additional
services within the pipeline (for
example associating session within a
request before HTTP handler executes,
and saving the session state after
HTTP handler has done its job, is
basically done by an HTTP module,
SessionStateModule)
In your case, HTTPModule will require to redirect the another web page.
using System;
using System.Web;
using System.Web.UI;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Data;
using System.Data;
namespace CustomHttpModule
{
public class HttpModuleImplementation : IHttpModule
{
#region IHttpModule Members
public void Dispose()
{
}
public void Init(HttpApplication context)
{
if (context == null)
throw new ArgumentNullException("Context == null");
context.AuthorizeRequest += new EventHandler(this.ProcessRequestHandler);
}
#endregion
private void DummpRequest(object sender, EventArgs e)
{
}
//first check that user.identity record exist in database
//If not then forward user to User registration page
private void ProcessRequestHandler(object sender, EventArgs e)
{
try
{
HttpApplication context = (HttpApplication)sender;
string strAbsoluteUri = context.Request.Url.AbsoluteUri.ToLower();
//check if request is accessing aspx page
if (strAbsoluteUri.Substring(strAbsoluteUri.Length - 5, 5).Contains(".aspx"))
{
string userName = context.User.Identity.Name;
//replace Test Module with DB call to validate user data
if (!CheckUserInDb(userName))
{
if (!strAbsoluteUri.Contains("mypage.aspx"))
redirectToRegistrationPage(context);
}
}
}
catch (Exception ex)
{
}
}
private void redirectToRegistrationPage(HttpApplication context)
{
context.Response.Redirect("http://" + context.Request.ServerVariables["HTTP_HOST"].ToString() + "Regpage.aspx", false);
}
private bool CheckUserInDb(string userName)
{
return true;
}
}
}
In SharePoint virtual directory web.config file you have to enter the following entry under section httpModules :
<add name="CustomHttpModule" type="CustomHttpModule.HttpModuleImplementation, CustomHttpModule" />
I'm using ASP.NET MVC 2 and have a login page that is secured via HTTPS. To ensure that the user always accesses those pages via SSL, I've added the attribute [RequireHttps] to the controller. This does the job perfectly.
When they have successfully logged in, I'd like to redirect them back to HTTP version. However, there isn't a [RequireHttp] attribute and I'm struggling to get my head around how I might achieve this.
The added (potential) complication is that the website when in production is hosted at the route of the domain, but for development and testing purposes it is within a sub directory / virtual directory / application.
Am I over-thinking this and is there an easy solution staring me in the face? Or is it a little more complex?
After a bit of digging, I went along the lines of rolling my own as there didn't appear to be a good built-in solution to this (as mentioned, there is a great one for MVC2 applications in the form of [RequireHttps]). Inspired by çağdaş's solution to this problem and I adapated to come up with the following code:
public class RequireHttp : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// If the request has arrived via HTTPS...
if (filterContext.HttpContext.Request.IsSecureConnection)
{
filterContext.Result = new RedirectResult(filterContext.HttpContext.Request.Url.ToString().Replace("https:", "http:")); // Go on, bugger off "s"!
filterContext.Result.ExecuteResult(filterContext);
}
base.OnActionExecuting(filterContext);
}
}
I can now add this to my Controller methods and it behaves (seemingly) as expected. If I redirect to the Index action on my controller from a HTTPS protocol, it will redirect to HTTP. It only allows HTTP access to the Index ActionResult.
[RequireHttp]
public ActionResult Index() {
return View();
}