I am using uploadify to upload files, they automatically post to the handler. I then modify the session in the handler that I have setup as a static property in a common class of the website. I then try to access that same session in the aspx page, and the value is null. I have a feeling this is because of cookies, but there needs to be a way to work around this without exposing the sessionid in the url.
ASHX:
public class Upload : IHttpHandler, IReadOnlySessionState, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
...
CMSSession.Current.UploadedFiles.Add(fileName);
}
}
Session Class:
public class CMSSession
{
public static CMSSession Current
{
get
{
CMSSession session = (CMSSession)HttpContext.Current.Session["__CMSSession__"];
if (session == null)
{
session = new CMSSession();
HttpContext.Current.Session["__CMSSession__"] = session;
}
return session;
}
}
public List<string> UploadedFiles { get; set; }
}
ASPX:
if (CMSSession.Current.UploadedFiles != null)
{
...
}
else
{
IT'S ALWAYS NULL
}
Web.Config:
<sessionState mode="InProc" cookieless="false" /> - causes session to always null in aspx when modified in ashx
<sessionState mode="InProc" cookieless="true" /> - session value is not null, but sessionid is exposed in the url
How do I access & modify the current session within the ASHX file WITHOUT changing cookieless to true and then access the session from the ASPX page?
I have tried using HttpContext and using the context passed into the ASHX...nothing works.
same as this question, but there has to be a more secure way: session set in ashx and get that session on aspx
Any ideas?
I found the answer: When the handler is being called from FLASH (like swfupload or uploadify) it does not pass the current sessionid to the handler. The handler then creates a NEW session. To fix this, do the following:
Your UI: JavaScript:
$(Selector).uploadify({
swf: 'uploadify.swf',
uploader: 'Upload.ashx?ASPSESSID=<%=Session.SessionID%>'
});
Add to: Global.asax:
void Application_BeginRequest(object sender, EventArgs e)
{
try
{
string session_param_name = "ASPSESSID";
string session_cookie_name = "ASP.NET_SESSIONID";
string session_value = Request.Form[session_param_name] ?? Request.QueryString[session_param_name];
if (session_value != null) { UpdateCookie(session_cookie_name, session_value); }
}
catch (Exception) { }
}
void UpdateCookie(string cookie_name, string cookie_value)
{
HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(cookie_name);
if (cookie == null)
{
HttpCookie cookie1 = new HttpCookie(cookie_name, cookie_value);
Response.Cookies.Add(cookie1);
}
else
{
cookie.Value = cookie_value;
HttpContext.Current.Request.Cookies.Set(cookie);
}
}
Taken & simplified for uploadify from:
http://snipplr.com/view/15180/
You may need to use an authid if using formsauthentication:
&AUTHID=<%= Request.Cookies[FormsAuthentication.FormsCookieName] == null ? "" : Request.Cookies[FormsAuthentication.FormsCookieName].Value %>
append that to the uploader parameter in the jQuery.
Then add the following to the global:
try
{
string auth_param_name = "AUTHID";
string auth_cookie_name = FormsAuthentication.FormsCookieName;
string auth_value = Request.Form[auth_param_name] ?? Request.QueryString[auth_param_name];
if (auth_value != null) { UpdateCookie(auth_cookie_name, auth_value); }
}
catch (Exception) { }
You can now access the same session from the handler (even using the static session object I used above in the question) in IE, Chrome, FF, ect.
Context.Session is null.. because connection to HttpHandler has another Context.Session
(debug and try: Context.Session.SessionId in where is the fileInput is different from Context.Session.SessionId in Upload.ashx)!
I suggest a workaround: pass a reference to the elements you need in the second session ( in my sample i pass the original SessionId using sessionId variable)
....
var sessionId = "<%=Context.Session.SessionID%>";
var theString = "other param,if needed";
$(document).ready(function () {
$('#fileInput').uploadify({
'uploader': '<%=ResolveUrl("~/uploadify/uploadify.swf")%>',
'script': '<%=ResolveUrl("~/Upload.ashx")%>',
'scriptData': { 'sessionId': sessionId, 'foo': theString },
'cancelImg': '<%=ResolveUrl("~/uploadify/cancel.png")%>',
....
and use this items in .ashx file.
public void ProcessRequest(HttpContext context)
{
try
{
HttpPostedFile file = context.Request.Files["Filedata"];
string sessionId = context.Request["sessionId"].ToString();
....
If you need to share complex elements use Context.Application instead of Context.Session, using original SessionID: Context.Application["SharedElement"+SessionID]
Related
I have a web system developed with ASP.NET MVC 4.
We have a user management that allows users to edit/delete other users.
On delete function, currently i'm doing only a delete on database.
So here is my login controller/method:
[HttpPost]
public ActionResult Login(LoginViewModel loginViewModel)
{
if (_loginService == null)
_loginService = new LoginService();
var result = _loginService.Login(loginViewModel.User, loginViewModel.Password);
if (!result.Error)
{
var userData = JsonConvert.SerializeObject(result.User);
FormsAuthentication.SetAuthCookie(result.User.Id, false);
var ticket = new FormsAuthenticationTicket(1, result.Id, DateTime.Now, DateTime.Now.AddMinutes(9999), true, userData, FormsAuthentication.FormsCookiePath);
var encryptedCookie = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedCookie) { Expires = DateTime.Now.AddHours(14) };
Response.Cookies.Add(cookie);
}
return new JsonResult
{
Data = result
};
}
And I treat that return on client side with some javascript. This is working fine by now.
For every Controller that user must be authenticated, I have [Authorize] attribute.
Lets say that I just logged in with user ABC. As long as ABC cookie is alive he can navigate fine.. the problem is when some user (lets say ZXC) deletes user ABC, he will still navigate fine until the cookie expires.
Is there a way to drop ABC session on IIS in the moment ZXC deletes him from database?
I don't know.. force a cookie expire. I just don't wanna implement a consult for each action done in navigation to check if the user is still "alive" in database.
Any ideas, suggestions?
Firstly, no. There is no way to access cookies in another session as they only exist for the lifetime of the request/response. However, you could store a static List of all current authenticated users and invalidate them that way.
This is a bit problematic because in the case that the App Pool recycles - all users will be 'logged out'. If this is not an issue for you (i.e. the app pool recycles at 2am and it is for a business system that does not operate at 2 am) then you can try this...
Code provided is untested
source: https://msdn.microsoft.com/en-us/library/system.web.security.formsauthenticationmodule.authenticate
EDIT:
I was not removing the cookie from the request and expiring it in the response.
In the Global.asax
private static List<string> _authenticatedUsers = new List<string>();
public static AuthenticateUser (MyApplicationUser user)
{
if(!_authenticatedUsers.ContainsKey(user.Username))
{
_authenticatedUsers.Add(user.Username);
}
}
public static DeauthenticateUser (MyApplicationUser user)
{
if(_authenticatedUsers.ContainsKey(user.Username))
{
_authenticatedUsers.Remove(user.Username);
}
}
public void FormsAuthentication_OnAuthenticate(object sender, FormsAuthenticationEventArgs args)
{
if (FormsAuthentication.CookiesSupported)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(
Request.Cookies[FormsAuthentication.FormsCookieName].Value);
MyApplicationUser user = JsonConvert.DeserializeObject(ticket.UserData);
if(user == null || !_authenticatedUsers.Any(u => u == user.Username))
{
// this invalidates the user
args.User = null;
Request.Cookies.Remove(FormsAuthentication.FormsCookieName);
HttpCookie myCookie = new HttpCookie(FormsAuthentication.FormsCookieName);
DateTime now = DateTime.Now;
myCookie.Value = "a";
myCookie.Expires = now.AddHours(-1);
Response.Cookies.Add(myCookie);
Response.Redirect(FormsAuthentication.LoginUrl);
Resonpse.End();
}
}
catch (Exception e)
{
// Decrypt method failed.
// this invalidates the user
args.User = null;
Request.Cookies.Remove(FormsAuthentication.FormsCookieName);
HttpCookie myCookie = new HttpCookie(FormsAuthentication.FormsCookieName);
DateTime now = DateTime.Now;
myCookie.Value = "a";
myCookie.Expires = now.AddHours(-1);
Response.Cookies.Add(myCookie);
Response.Redirect(FormsAuthentication.LoginUrl);
Resonpse.End();
}
}
}
else
{
throw new HttpException("Cookieless Forms Authentication is not " +
"supported for this application.");
}
}
In your login action
public ActionResult Login(LoginViewModel loginViewModel)
{
...
if (!result.Error)
{
...
MvcApplication.AuthenticateUser(result.User);
...
}
...
}
In your logout action
public ActionResult Logout(...)
{
...
MvcApplication.DeauthenticateUser(user);
...
}
In your delete method
...
MvcApplication.DeauthenticateUser(user);
...
I have a PHP page running on IIS8.
Authentication is done through ADFS.
I would like to access the values of some of the claims in the user's SAML token from the PHP page, but I think those values are not stored anyway.
I tried creating a custom HttpModule to pass values to the PHP page:
using Microsoft.IdentityModel.Claims;
using System;
using System.Threading;
using System.Web;
public class TestModule : IHttpModule {
public void Init(HttpApplication context) {
context.AuthenticateRequest += Context_AuthenticateRequest;
}
private void Context_AuthenticateRequest(object sender, EventArgs e) {
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
IClaimsPrincipal principal = Thread.CurrentPrincipal as IClaimsPrincipal;
if (principal == null || principal.Identities == null || principal.Identities.Count == 0) {
context.Response.Write("TestModule: cannot get claims.<br/>");
return;
}
IClaimsIdentity identity = principal.Identities[0];
foreach (Claim claim in identity.Claims) {
if (claim.ClaimType == "http://schemas.xmlsoap.org/claims/DisplayName") {
context.Response.Write("TestModule: setting USER_DISPLAY_NAME to " + claim.Value + "<br/>");
Environment.SetEnvironmentVariable("USER_DISPLAY_NAME", claim.Value);
}
}
}
public void Dispose() {
}
}
This is executed, and the variable is set to the good value.
In the PHP page I have this:
<?php
echo getenv('USER_DISPLAY_NAME');
?>
But nothing is displayed.
Is it possible to pass a variable to a PHP page with a custom module?
Is there another more standard way to get ADFS claims values from a PHP page in IIS?
Actually I am trying to send data from .aspx to .ashx file. I am using Session in .aspx and trying to get value of session in .ashx but it is showing exception:: Object reference not set to an instance of an object.
Here is my code :-
.aspx code
[WebMethod(enableSession:true)]
public static string SetId(string Id)
{
HttpContext.Current.Session["MId"] = Id.ToString(); Console.Write(" ");
string session = HttpContext.Current.Session["MId"].ToString(); // Here I am getting value
//string session = HttpContext.Current.Session["MId"].ToString();
//BatchReadEmails.EmailProperties session = new BatchReadEmails.EmailProperties();
//session.MailId = Id.ToString();
return "Ok";
}
I am getting value in string session.
.ashx code:-
public class ChangeLogHandler : IHttpHandler, System.Web.SessionState.IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
HttpRequest request = context.Request;
HttpResponse response = context.Response;
string session = "";
if (context.Session["MId"] != null)
session = context.Session["MId"].ToString();
else
session = "Hello India";
}
}
Here it is showing session = "Hello India"
My Question:-
Is there any way to send data from .aspx to .ashx file??
I checked so many links all are using if for null but I already check in .aspx file it is showing value there but showing null in .ashx file Why?? (For exceptional cases we can use/ write if condition but I already checked string session has value.
Am I missing something?? Thanks
These are the links I already used:-
How to access Session in .ashx file?
Accessing context session variables in c#
In the aspx you're adding Session["MId"]. In the ashx you're reading Session["MailId"].
Make the keys you're using the same. (ie either MId or MailId, but not both).
Would suggest you define a constant to define this value since it's shared, then you can avoid such problems.
Now it's working.I did these changes:-
Instead of
[WebMethod(enableSession:true)]
I put
[WebMethod(EnableSession = true)]
But Both are the correct way.
And I include
async: false in my ajax call. (I think before setting the session it was trying to read it)
This code worked for me well
protected void Button1_Click(object sender, EventArgs e)
{
Session["MailId"] = "somemail#address.com";
Response.Redirect("Handler.ashx");
}
/// Code in ashx
public class Handler : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest (HttpContext context)
{
string sessionValue = context.Session["MailId"].ToString();
context.Response.Write(sessionValue);
}
public bool IsReusable {
get {
return false;
}
}
}
I like to know whether u accessing handler from an ajax call or not
I've got webform routing setup on my asp.net webforms 3.5sp1 project. I would like to have the files for the site in a directory called content including the home page as I would like to run multiple sites using the same system.
In MVC there is a blank default page and the home page is in a folder called home. I can't seem to replicate this behaviour using web form routing but would like to. The blank page is always hit first. the route handler is hit second - it recognises that the request is for the home page and sets up the routing page but is not used. the route handler code is simple:
public string VirtualPath { get; private set; }
public IHttpHandler GetHttpHandler(RequestContext
requestContext)
{
string file = requestContext.RouteData.GetRequiredString("File");
string id = requestContext.RouteData.GetRequiredString("Id");
string queryString = "?menuid=" + id;
VirtualPath = "~/" + file;
HttpContext.Current.RewritePath(
string.Concat(
VirtualPath,
queryString));
var page = BuildManager.CreateInstanceFromVirtualPath
(VirtualPath, typeof(Page)) as IHttpHandler;
return page;
}
Is there anyway I can do this?
Update
Here is my global.asax route code:
public static void RegisterRoutes(RouteCollection routes)
{
Domain.RepositoryFactory repo = new RepositoryFactory();
foreach (var x in repo.MenuRepository.GetAllEnabledGetMenus())
{
if (string.IsNullOrEmpty(x.Url))
{
//add default
System.Web.Routing.RouteTable.Routes.Add(
new Route("Default.aspx",
new RouteValueDictionary(new { File = x.FileName,
Id = x.Id.ToString() }),
new CoreRouteHandler()));
}
else
{
string url = x.Url;
if(x.Url.StartsWith("/"))
{
url = url.Remove(0, 1);
}
System.Web.Routing.RouteTable.Routes.Add(
new System.Web.Routing.Route(url,
new RouteValueDictionary(new {File = x.FileName,
Id = x.Id.ToString()}),
new CoreRouteHandler()));
}
}
}
In my project I was needed to redirect all calls like www.site.com/MyPage to /Pages/MyPage.aspx. Was done by using HttpModule. Sample code below:
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
if (app.Context == null || app.Context.Response == null)
return;
String sourceUrl = String.Empty;
try
{
sourceUrl = app.Request.FilePath.TrimStart('/').TrimEnd('/').ToLower();
if (global::MyProject.Global.UrlShortcuts.ContainsKey(sourceUrl))
{
String newUrl = global::MyProject.Global.UrlShortcuts[sourceUrl];
app.Context.RewritePath(newUrl, string.Empty, app.Request.QueryString.ToString(), false);
}
else
{
}
}
catch (Exception Ex)
{
// handle your exception here
}
}
The minor issue was with hoster's IIS as I was unable to configure it to process all requests using ASP.NET. So I had to come up with blank placeholder .aspx files for pages (e.g. www.site.com/MyPage/default.aspx) created dynamically at application startup if it's running under IIS.
String server = Context.Request.ServerVariables["SERVER_SOFTWARE"];
// IIS puts some stuff here, WebDev server leaves the field empty
ok I got it working bit of a doh! moment.
I found this link while googling:
http://blog.ysatech.com/post/2010/07/11/ASP-NET-4-URL-Routing-Default-Page.aspx
all I needed to do was leave the route blank and delete the default.aspx file from the root of the site.
I also copied in the default system.webserver bis from a new MVC project as i think what i had there wasn't right. I'm upgrading an old project and so think it wasn't configured 100%. specifically: was missing.
I have built a shopping cart that uses Session State to keep the shopping cart data while the user is browsing the store.
I have an issue where if I leave the browser window open for a long time on step1 of the shopping cart, then press "go to step 2", my actions throw an error because the step2 action assumes the session hasn't expired and the ShopCart object is in the correct state.
I would like this scenario to be nicer for my users, but I think i need to somehow detect if the session has expired so that on next request I can throw them to Step1.
I found the following code that claims to to solve the problem, but it doesn't work for me.
The IsNewSession condition is true but the condition
if ((null != sessionCookie) && (sessionCookie.IndexOf("ASP.NET_SessionId") >= 0)) {
// handle expired session
}
always returns false and it never handles the invalid session. I'm confused.
Is this possible in ASP.NET (and MVC)?
Way 1
Put this code in the Init / Load event of Page 2...
if (Context.Session != null)
{
if (Context.Session.IsNewSession)
{
string sCookieHeader = Request.Headers["Cookie"];
if ((null != sCookieHeader) && (sCookieHeader.IndexOf("ASP.NET_SessionId") >= 0))
{
if (Request.IsAuthenticated)
{
FormsAuthentication.SignOut();
}
Response.Redirect("Error Page");
}
}
}
Way 2
Alternative you can check whether the Session object exists before proceeding to work with it in Page 2, like this:
if (Session["Key"] != null)
{
Object O1 = (Object) Session["Key"];
}
else
{
Response.Redirect("ErrorPage.aspx");
}
The King 's answer does not work for me. I have added FormsAuthentication.SignOut() in OnActionExcuting(). The Response.Redirect will not work!
if (Request.IsAuthenticated)
{
FormsAuthentication.SignOut();
}
This is my complete method
public class SessionExpireFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext ctx = HttpContext.Current;
// check if session is supported
if (ctx.Session != null)
{
// check if a new session id was generated
if (ctx.Session.IsNewSession)
{
// If it says it is a new session, but an existing cookie exists, then it must
// have timed out
string sessionCookie = ctx.Request.Headers["Cookie"];
if ((null != sessionCookie) && (sessionCookie.IndexOf("ASP.NET_SessionId") >= 0))
{
string redirectOnSuccess = filterContext.HttpContext.Request.Url.PathAndQuery;
string redirectUrl = string.Format("?ReturnUrl={0}", redirectOnSuccess);
string loginUrl = FormsAuthentication.LoginUrl + redirectUrl;
if (ctx.Request.IsAuthenticated)
{
FormsAuthentication.SignOut();
}
RedirectResult rr = new RedirectResult(loginUrl);
filterContext.Result = rr;
//ctx.Response.Redirect("~/Home/Logon");
}
}
}
base.OnActionExecuting(filterContext);
}
}
You need to create the Session_OnEnd method In Global.asax.cs file in your project.
this is my code and I am able to Detecting Session expiry on ASP.NET MVC
protected void Session_OnEnd(object sender, EventArgs e)
{
int userid = 0;
userid = Convert.ToInt32(Session["UserID"]);
if (userid != 0)
{
var userActivity = DependencyResolver.Current.GetService<IUserRepo>();
var responce = userActivity.LogOutUsers(userid);
if (responce == true)
{
Session.Clear();
Session.Abandon();
}
}
}
more