I've got a simple controller action that sets a Session variable called "firm" to my validated model.
[HttpPost]
public ActionResult ClientProfile(ClientProfileFormModel model)
{
if (ModelState.IsValid)
{
System.Web.HttpContext.Current.Session["firm"] = model;
return View("ClientProfileConfirmation",model);
}
return View(model);
}
After the user clicks a link to confirm, the link sends them to this action:
public ActionResult ClientProfileConfirmationSubmit()
{
var model = (ClientProfileFormModel)System.Web.HttpContext.Current.Session["firm"];
string emailToAdminBody = GenerateFirmProfileAdminEmail(model);
EmailLogic.Instance.SendEmail("test#test.com", "test#test.com", "Firm profile from " + model.FirmAddress.Name, emailToAdminBody);
return View(model);
}
My issue is: model is null. Through the debugger, I can confirm that the "firm" session variable is set. But when the second action is entered, the session variable is no longer there, and model gets set to null. I'm stumped as to what this could be. I've scoured Stackoverflow for solutions.
I've tried both System.Web.HttpContext.Current.Session[] and just Session[].
I've tried adding the SessionStateModule like this answer suggests: HttpContext.Current.Session is null when routing requests
I've tried manually starting the ASP State Service on my local machine.
I've even tried changing the model to a simple string, and trying to retrieve that, with no luck, so it can't be the model causing an issue.
Turns out I didn't have sessions enabled in my web.config.
<configuration>
...
<system.web>
<pages enableSessionState="true">
<controls>
...
</controls>
</pages>
...
<sessionState cookieless="AutoDetect" mode="StateServer" timeout="22" />
</system.web>
...
</configuration>
Related
I have an ASP.NET 4.6 project that uses MVC controllers that return my views and WebAPI Controllers that return data.
I want to add output caching to my MVC controllers because I've done a few tests and the performance difference on page load is massive.
[OutputCache(CacheProfile = "PageCache")]
public ActionResult Home()
{
return View("~/Views/Home/Index.cshtml");
}
The only challenge I'm facing is that the razor syntax on the views is also cached.
For example if user 1 loads a route, user 2 will get the same route with the username injected from user 1.
Besides getting rid of all the razor syntax in the pages, what are my options? Does anyone have a good solution to this problem?
You can use VaryByCustom or VaryByParam attributes. The following code is the cache based on the parameter 'id'.
[OutputCache(Duration = int.MaxValue, VaryByParam = "id")]
public ActionResult Details(int id)
{
ViewData.Model = _dataContext.Movies.SingleOrDefault(m => m.Id == id);
return View();
}
You can create a cache profile also in the web.config file
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<add name="Cache1Hour" duration="3600" varyByParam="none"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
For more info check this Link
You should not cache user information on the server, it should be cached on the client.
Please take a look at this document.
https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/controllers-and-routing/improving-performance-with-output-caching-cs
I’m suffering this issue I can’t find an explanation for.
Have a website that handles ASP and ASPX requests.
All requests run through a custom managed module, named MyModule, let’s say for “logging purposes”.
This is the WebConfig:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="MyModule" type="MySample.MyModule" preCondition="managedHandler" />
</modules>
</system.webServer>
</configuration>
So, if a form is posted to /action.asp via AJAX, an html form, or whatever, on /action.asp I can see and print the data on the Request.Form collection.
This is /action.asp
<%#LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<%
dim count
count = Request.Form.Count
Response.write("Result: " & count)
Response.End()
%>
But, if in my custom managed module I just “PEEK” at the form collection before it’s handled by the ASP page, the collection disappears, it’s no longer available to /action.asp
This is the MyModule:
namespace MySample
{
public class MyModule : IHttpModule
{
public MyModule()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += context_BeginRequest;
}
void context_BeginRequest(object sender, EventArgs e)
{
/*
* ALL REQUESTS PASS THROUGH THIS POINT BEFORE CONTINUING.
* COUNTING THE ITEMS ON THE FORM WILL CAUSE THE FORM-COLLECTION
* TO BE CLEARED WHEN IT'S HANDLED BY ASP.
*/
int count = HttpContext.Current.Request.Form.Count;
}
public void Dispose()
{
}
}
}
It’s extremely odd. If I “comment” the count line, the form collection is handled unmodified to the ASP page. I just have to peek at it to run it.
I want to find an explanation for this backed up with some documentation, not just a hunch.
I can’t set to false the runAllManagedModulesForAllRequests, this is not an option.
I debugged the request through different .NET method calls, and many things happen when you query the Form object on .NET HttpRequest object,
// Form collection
/// Gets a collection of Form variables.
public NameValueCollection Form {
get {
EnsureForm();
if (_flags[needToValidateForm]) {
_flags.Clear(needToValidateForm);
ValidateHttpValueCollection(_form, RequestValidationSource.Form);
}
return _form;
}
}
// Populates the Form property but does not hook up validation.
internal HttpValueCollection EnsureForm() {
if (_form == null) {
_form = new HttpValueCollection();
/// THE FOLLWING METHOD AS A LOT OF SUB-CALLS AS WELL
if (_wr != null)
FillInFormCollection();
_form.MakeReadOnly();
}
return _form;
}
Is what I am experiencing an expected behavior ? What’s the documentation or the reasoning to back up this behavior ?
I have a "OperaMini" displaymode, and then a _Layout.OperaMini.cshtml layout.
This works okay, until I add Output caching. I use this cache profile:
<add name="Cache1HourVaryByAll" duration="3600" enabled="true" varyByParam="*" />
If the first hit on a page is from an OperaMini user agent, then all subsequent requests (regardless of their user agent) get the OperaMini page.
I have tried suggestions listed on this workitem, FixedDisplayModes etc but I cant get it to work.
I also use HttpRuntime.Cache for some objects, could this be causing issues?
This was supposed to be fixed in MVC5? Or am I doing something wrong?
You'll have to introduce a (pseudo) Vary-By-DisplayMode mechanism:
Global.asax:
public override string GetVaryByCustomString(HttpContext context, string arg)
{
if (arg.ToLower() == "displaymode")
{
var currentDisplayMode = DisplayModeProvider.Instance.Modes.FirstOrDefault(x => x.CanHandleContext(new HttpContextWrapper(context)));
return "displayMode=" + currentDisplayMode.DisplayModeId;
}
return base.GetVaryByCustomString(context, arg);
}
Web.Config:
<add name="Cache1HourVaryByAll"
duration="3600"
enabled="true"
varyByParam="*"
varyByCustom="displaymode" />
In an MVC5 application I am using Windows Authentication and wanted to use our Active Directory Groups as roles as this is strictly and intranet application. I am using the WindowsTokenRoleProvider as so:
<roleManager defaultProvider="WindowsProvider" enabled="true" cacheRolesInCookie="false">
<providers>
<add name="WindowsProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
</providers>
</roleManager>
I have tried a few other variations of that config including using the cookie cache, but the end result is that it takes ~20 seconds per group check. I check role like this:
User.IsInRole(#"Domain\UserName")
Is there something I have completely missed in setting this up? I can't believe it would be normal for authentication to take 20 seconds per check. The user I am checking is in ~50 groups, but I didn't think that would be enough to slow it down so much.
So best solution at this point seems to be this stackoverflow question
I will probably play around with how the roles get checked/added to see if I can pinpoint the issue, but I wouldn't expect this slowness from only being in 50 groups.
UPDATE:
So while actually enumerating my groups I found my user was in over 400 groups which might explain why it took so long. I still don't under stand why the IsInRole method on user would call GetRolesForUser instead of just calling IsUserInRole directly, but this makes things exponentially faster
UPDATE 2:
Old answer was deleted so here is my class:
public class CustomWindowsTokenRoleProvider : WindowsTokenRoleProvider
{
public override string[] GetRolesForUser(string username)
{
List roles = null;
string key = String.Concat(username, ":", base.ApplicationName);
Cache cache = HttpContext.Current.Cache;
if (cache[key] != null)
{
roles = new List(cache[key] as string[]);
}
if (roles == null)
{
roles = new List();
// AppSettings.APPLICATION_GROUPS is an IEnumerable that returns just the groups that my application is interested in checking against
foreach (string role in AppSettings.APPLICATION_GROUPS)
{
if (base.IsUserInRole(username, role));
{
roles.Add(role);
}
}
cache.Insert(key, roles.ToArray(), null, DateTime.Now.AddHours(1), Cache.NoSlidingExpiration);
}
return roles.ToArray();
}
}
I'm just getting started with ASP.NET and the MVC model. I've worked my around the basic concepts and have a few models, controllers, and views working fine. I know how to add Web Methods and Page Methods to a Web Service, but cannot figure it out for MVC projects.
I (think) I need to add a Page Method to my project as the correct way of responding to AJAX requests. This is what my controller looks like:
namespace MyProject
{
public class OrderController : Controller
{
public ActionResult Place (ProductSku sku)
{
var order = Order.NewOrder(sku);
var db = new SystemDiscsLib.Database();
db.SaveOrder(order);
return View(order);
}
[WebMethod]
public static string GetDate ()
{
return DateTime.Now.ToString();
}
POSTing to /Order/Place works fine, and the view is created displaying the contents of Views/Order/Place.aspx and everyone is happy. However, any requests made to /Order/GetDate fail with a The resource cannot be found error. I (think) I have correctly enabled Page Methods by adding this to my Web.config, under system.web:
<httpModules>
<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</httpModules>
I do not have a view called GetDate as I don't want a view, I'll just be returning JSON data. I intend to use JQuery, so I didn't do the EnablePageMethods and ScripManager stuff, per this article.
PageMethods are for WebForms, not MVC. Change your method to look more like this:
public JsonResult GetDate()
{
return Json(DateTime.Now.ToString());
}
Note that the method is no longer static, and you should not use the [WebMethod] attribute.