I am busy converting a web application to MVC and have some information saved to Application variables used across multiple tenants/accounts to make things a bit more efficient.
I realise the point of MVC is to keep things as stateless as possible, Sesion State obviously makes sense to have and exists in MVC but we dont want to just convert Application to Session variables as we would rather have something more global and more secure. Do MVC applications have Application Variables? I have seen some examples where caching is used? Is this now standard and How robust/secure is this compared to Application/Session State?
Yes, you can access Application variables from .NET MVC. Here's how:
System.Web.HttpContext.Current.Application.Lock();
System.Web.HttpContext.Current.Application["Name"] = "Value";
System.Web.HttpContext.Current.Application.UnLock();
Session state or the Cache are better choices. They are mockable in MVC and are designed to store session and application-scoped data.
Static classes seems like a popular choice here. However static classes create dependencies between your types and make versioning/testing harder. Its also a bit of an odd pattern to use in a framework that is designed to break apart these kinds of dependencies. For instance, the standard ASP.NET framework is riddled with statics and sealed types. These are all replaced with mock-able instances.
"Secure" is a bit unclear in this context. Exactly what do you mean by "secure?"
I implemented something like below as an Extension for Global state variable. I put things like Site title,Service Endpoints, authorized roles
public static class ApplicationStateExtension
{
public static T GetSetApplicationState<T>(this HttpApplicationState appState, string objectName, object objectValue = null, int syncCheckMinutes = 0)
{
T retVal = default(T);
appState.Lock();
if (appState[objectName + "LastSync"] == null || DateTime.Now.Subtract(((DateTime)appState[objectName + "LastSync"])).TotalMinutes >= syncCheckMinutes)
{
appState[objectName + "LastSync"] = DateTime.Now;
if (objectValue != null)
appState[objectName] = objectValue;
}
if (appState[objectName] != null)
retVal = (T)appState[objectName];
appState.UnLock();
return retVal;
}
public static object GetSetApplicationState(this HttpApplicationState appState, string objectName, object objectValue = null, int syncCheckMinutes = 0)
{
object retVal = null;
appState.Lock();
if (appState[objectName + "LastSync"] == null || DateTime.Now.Subtract(((DateTime)appState[objectName + "LastSync"])).TotalMinutes >= syncCheckMinutes)
{
appState[objectName + "LastSync"] = DateTime.Now;
if (objectValue != null)
appState[objectName] = objectValue;
}
if (appState[objectName] != null)
retVal = appState[objectName];
appState.UnLock();
return retVal;
}
public static void SetApplicationState(this HttpApplicationState appState, string objectName, object objectValue, int syncCheckMinutes = 0)
{
appState.Lock();
if (appState[objectName + "LastSync"] == null || DateTime.Now.Subtract(((DateTime)appState[objectName + "LastSync"])).TotalMinutes >= syncCheckMinutes)
{
appState[objectName + "LastSync"] = DateTime.Now;
appState[objectName] = objectValue;
}
appState.UnLock();
}
public static object GetApplicationState(this HttpApplicationState appState, string objectName)
{
object retVal = null;
appState.Lock();
if (appState[objectName] != null)
retVal = appState[objectName];
appState.UnLock();
return retVal;
}
public static T GetApplicationState<T>(this HttpApplicationState appState, string objectName)
{
T retVal = default(T);
appState.Lock();
if (appState[objectName] != null)
retVal = (T)appState[objectName];
appState.UnLock();
return retVal;
}
}
So I can set them from Global.asax.cs something like this
Application.SetApplicationState("UISiteTitle",paramHelper.GetUIConfigXML<XMLParams.UISiteOptions>("UISiteOptions")
.SiteOptionCollection.Where(v => v.name.Equals("title", StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault().value););
or
var uiPermissions = Application.GetSetApplicationState<XMLParams.UIPermissions>("UIPermissions", paramHelper.GetUIConfigXML<XMLParams.UIPermissions>("UIPermissions"), 30);
You can declare Application variables in Application_Start like this:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
var e = "Hello";
Application["value"] = e;
}
To access this on controller write:
string appVar = HttpContext.Application["value"] as string;
Make a static class?
Do they have Application Variables? Yes, MVC is a framework that sits on top of the normal asp.net framework.
I would however create a static class that uses a cache store as it's backing.
Related
I have an app with repository pattern. It allows me to manipulate objects via LINQ, objects are stored in memory, so I can access them very fast. Here a sample code:
private Measurement ParseExact(AgentParameter agentParameter)
{
ControlledElement ce;
using (var repositoryBase = Datastore.GetRepository<ControlledElement>())
{
var mvId = Convert.ToInt32(agentParameter.ControlledParameterId);
var sId = Convert.ToInt32(agentParameter.FacilityId);
ce =
repositoryBase.Query(
t => t.FirstOrDefault(elem => elem.Sensor.Id == sId && elem.MeasuringValue.Id == mvId));
}
}
When I profiled my code with dotTrace I found that on high load I get a performance lack on creating delegate elem => elem.Sensor.Id == sId && elem.MeasuringValue.Id == mvId. My Query method looks like:
public TOut Query<TOut>(Func<IQueryable<TEntity>, TOut> specification) which means, that I really pass a Func<> object every time I use it. So, the question is, how can I optimize this?
EDIT proof of lack on creation and compilation
You can eliminate the compilation step by explicitly tracking the state in an object, rather than using a closure.
private Measurement ParseExact(AgentParameter agentParameter)
{
ControlledElement ce;
using (var repositoryBase = Datastore.GetRepository<ControlledElement>())
{
var mvId = Convert.ToInt32(agentParameter.ControlledParameterId);
var sId = Convert.ToInt32(agentParameter.FacilityId);
var query = new ParseExactQuery(mvId, sId);
ce = repositoryBase.Query(t => t.FirstOrDefault(query.Query));
}
}
private class ParseExactQuery {
private int mvId;
private int sId;
public ParseExactQuery (int mvId, int sId) {
this.mvId = mvId;
this.sId = sId;
}
public bool Query(ControlledElement elem) {
return elem.Sensor.Id == sId && elem.MeasuringValue.Id == mvId;
}
}
I cannot figure out how to fix this loop issue when i call a function like
new Common.Utility.Parameter().Get(Common.Constants.Parameter.SomeParameter);
Probably the error is caused by isHttpsCookie that recall the Parameter.Get()
Utility.cs
public static class Utility
{
public class Parameter
{
public string Get(string key)
{
string cookie = new Cookie().Read(key);
if (cookie == null)
{
var parameter = new Models.Parameter();
using (var db = new MyEntities())
parameter = db.Parameters.Where(w => w.Key == key).FirstOrDefault<Models.Parameter>();
if (parameter != null)
{
new Cookie().Write(key, parameter.Value);
return parameter.Value;
}
else
return string.Empty;
}
else
return cookie;
}
}
}
Cookie.cs
public class Cookie
{
private bool isHttpsCookie = Convert.ToBoolean(new Utility.Parameter().Get(Constants.Parameter.IsHttps)); // Loop here?
public string Read(string cookieName)
{
HttpCookie httpCookie = HttpContext.Current.Request.Cookies[HttpContext.Current.ApplicationInstance.GetType().BaseType.Assembly.GetName().Name + "_" + cookieName];
return httpCookie != null ? HttpContext.Current.Server.HtmlEncode(httpCookie.Value).Trim() : string.Empty;
}
public void Write(string cookieName, string cookieValue, bool isHttpCookie = true)
{
if (isHttpsCookie)
isHttpCookie = false;
var aCookie = new HttpCookie(HttpContext.Current.ApplicationInstance.GetType().BaseType.Assembly.GetName().Name + "_" + cookieName)
{Value = cookieValue, Expires = Common.Constants.Cookie.DefaultExpires, HttpOnly = isHttpCookie};
HttpContext.Current.Response.Cookies.Add(aCookie);
}
}
Apparently, your code is falling into a sort of recursion where you suspect it is. What I'm having trouble with is why are you creating new objects just to call a single method. Looks like you could have them as static methods in your classes, so no object creation would be needed, thus no 'looping'.
Have a closer look at your Cookie.Write() and Parameter.Get() method, they are calling each other. When you declare isHttpsCookie, you call Parameter.Get(). In the Parameter.Get(), if the condition is valid, it will call to Cookie.Write(). In its turn, when you call new Cookie(), the isHttpsCookie is called again and it's continuing forever.
Another point at this code:
if (isHttpsCookie)
isHttpCookie = false;
do you try to say that isHttpsCookie should be false at all time? so why do you need to declare this?
Solution: Do like #Takeshi said: those methods can be declared as static so no class declaration is required to called them.
You are correct in what you suspect. the isHttpsCookie declaration is causing you grief.
When the Cookie object is created it goes away and executes the method get from your utility class which creates an instance of cookie. Therefor you have your recursion.
You will need to change the way you initialise isHttpsCookie. Maybe only initialise / check if you are doing a write. After all you are most likely going to read more often than write.
Hope that helps.
I've found FluentValidation only couple of hours ago and I want to rewrite all my validation logic so it will use only FV.
The issue that I have ATM is that I would like to use data coming from input as a parameter for DomainExists() method. Is it possible or do I have to figure out a way around FV to achieve that?
public QuoteValidator()
{
// hardcoded because don't know how to pass input string to RuleFor
var inputeddomain = "http://google.com";
RuleFor(r => r.Domain).NotEqual(DomainExists(inputeddomain));
}
// checks if inputeddomain is in repository (SQL DB)
private string DomainExists(string inputeddomain)
{
var context = new QuoteDBContext().Quotes;
var output = (from v in context
where v.Domain == inputeddomain
select v.Domain).FirstOrDefault();
if (output != null) { return output; } else { return "Not found"; }
}
Thanks to #bpruitt-goddard hint I got that to work. Here's a solution to my problem (hope it will help somebody).
public QuoteValidator()
{
RuleFor(r => r.Domain).Must(DomainExists).WithMessage("{PropertyValue} exists in system!");
}
private bool DomainExists(string propertyname)
{
var context = new QuoteDBContext().Quotes;
var output = (from v in context
where v.Domain == propertyname
select v.Domain).FirstOrDefault();
if (output != null) { return false; } else { return true; }
}
You can use FluentValidation's Must method to pass in extra data from the input object.
RuleFor(r => r.Domain)
.Must((obj, domain) => DomainExists(obj.InputDomain))
.WithErrorCode("MustExist")
.WithMessage("InputDomain must exist");
Although this will work, it is not recommended to check for database existence in the validation layer as this is verification versus validation. Instead, this kind of check should be done in the business layer.
All, a while back (when I was rushed off my feet) I asked the following question Performace Overheads when Using Resource Files (.resx) regarding the performance overhead of using resource strings. I got an up-voted answer and took the answer to be correct. However, before, I was localising message strings which are called in error conditions and not performance critical - now I have been asked to implement localisation to our codes 'power-house' (lots of performance critical code, embedded loops etc.).
Having some time to look into this in more detail and I noticed that calling a resource like
Resources.MessageStrings.SomeResourceName
merely refers the call to the auto-generated code MessageStrings.Designer.cs, which uses
internal static string SomeResourceName {
get {
return ResourceManager.GetString("SomeResourceName", resourceCulture);}
}
So digging deeper, I thought I would decompile ResourceManager which is found in
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.5\mscorlib.dll
To see what GetString() was doing [Is it really caching my resource strings?]. Decompiling, I find
[__DynamicallyInvokable]
public virtual string GetString(string name, CultureInfo culture)
{
if (name == null)
throw new ArgumentNullException("name");
if (ResourceManager.s_IsAppXModel && object.ReferenceEquals((object) culture, (object) CultureInfo.CurrentUICulture))
culture = (CultureInfo) null;
if (this._bUsingModernResourceManagement)
{
if (this._PRIonAppXInitialized)
return this.GetStringFromPRI(name, culture == null ? (string) null : culture.Name, this._neutralResourcesCulture.Name);
if (this._PRIExceptionInfo == null || this._PRIExceptionInfo._PackageSimpleName == null || this._PRIExceptionInfo._ResWFile == null)
throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_NoPRIresources"));
throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_ResWFileNotLoaded", (object) this._PRIExceptionInfo._ResWFile, (object) this._PRIExceptionInfo._PackageSimpleName));
}
else
{
if (culture == null)
culture = Thread.CurrentThread.GetCurrentUICultureNoAppX();
if (FrameworkEventSource.IsInitialized)
FrameworkEventSource.Log.ResourceManagerLookupStarted(this.BaseNameField, this.MainAssembly, culture.Name);
ResourceSet resourceSet1 = this.GetFirstResourceSet(culture);
if (resourceSet1 != null)
{
string #string = resourceSet1.GetString(name, this._ignoreCase);
if (#string != null)
return #string;
}
foreach (CultureInfo culture1 in new ResourceFallbackManager(culture, this._neutralResourcesCulture, true))
{
ResourceSet resourceSet2 = this.InternalGetResourceSet(culture1, true, true);
if (resourceSet2 != null)
{
if (resourceSet2 != resourceSet1)
{
string #string = resourceSet2.GetString(name, this._ignoreCase);
if (#string != null)
{
if (this._lastUsedResourceCache != null)
{
lock (this._lastUsedResourceCache)
{
this._lastUsedResourceCache.lastCultureName = culture1.Name;
this._lastUsedResourceCache.lastResourceSet = resourceSet2;
}
}
return #string;
}
else
resourceSet1 = resourceSet2;
}
}
else
break;
}
if (FrameworkEventSource.IsInitialized)
FrameworkEventSource.Log.ResourceManagerLookupFailed(this.BaseNameField, this.MainAssembly, culture.Name);
return (string) null;
}
}
Nothing in the above code suggests that it is 'caching' my strings (in the typical/truest sense of the word), it seems it is doing a complex look-up of some type. I noticed that the method was using the undocumented __DynamicallyInvokable attribute, and found a breaf discussion of this attribute by Hans (What is the __DynamicallyInvokable attribute for?).
My question is: For performance critical code can I rely on the ResourceManager being fast enough (does it cache my strings?), or do I need to pre-process and cache the resource strings myself?
Thanks for your time.
The ressources are cached. If you follow the call stack through the resource manager it is like this:
1.
[System.Security.SecuritySafeCritical] // auto-generated
public virtual String GetString(String name, CultureInfo culture) {
//...
String value = rs.GetString(name, _ignoreCase);
//...
}
2.
public virtual string GetString(string name, bool ignoreCase)
{
object objectInternal = this.GetObjectInternal(name);
//...
}
3.
private object GetObjectInternal(string name)
{
//...
Hashtable hashtable = this.Table;
//...
return hashtable[(object) name];
}
So at this point the values is read from the hashtable.
The hashtable is filled once the ressource file is accessed:
Constructor:
[SecuritySafeCritical]
public ResourceSet(string fileName)
{
this.Reader = (IResourceReader) new ResourceReader(fileName);
this.CommonInit();
this.ReadResources();
}
and the ReadResources:
protected virtual void ReadResources()
{
IDictionaryEnumerator enumerator = this.Reader.GetEnumerator();
while (enumerator.MoveNext())
{
object obj = enumerator.Value;
this.Table.Add(enumerator.Key, obj);
}
}
The things that are being held in memory are things like the ResourceSets that it's working with, and those seem to directly hold the strings. You don't necessarily see it inside this method because at this point, every call could be coming in for different resource names and different cultures.
And, as always, is this where your profiling has told you that you have a performance issue? It's rarely, if ever, a good idea to try to optimize code by guessing at places that might be inefficient.
I am attempting to update a project from ASP.NET MVC Preview 3 to Preview 5 and it seems that Controller.ReadFromRequest(string key) has been removed from the Controller class. Does anyone know of any alternatives to retrieving information based on an identifier from a form?
Looks like they've added controller.UpdateModel to address this issue, signature is:
UpdateModel(object model, string[] keys)
I haven't upgraded my app personally, so I'm not sure of the actual usage. I'll be interested to find out about this myself, as I'm using controller.ReadFromRequest as well.
Not sure where it went. You could roll your own extension though:
public static class MyBindingExtensions
{
public static T ReadFromRequest < T > (this Controller controller, string key)
{
// Setup
HttpContextBase context = controller.ControllerContext.HttpContext;
object val = null;
T result = default(T);
// Gaurd
if (context == null)
return result; // no point checking request
// Bind value (check form then query string)
if (context.Request.Form[key] != null)
val = context.Request.Form[key];
if (val == null)
{
if (context.Request.QueryString[key] != null)
val = context.Request.QueryString[key];
}
// Cast value
if (val != null)
result = (t)val;
return result;
}
}
could you redo that link in something like tinyurl.com?
I need this info too but can get that mega-link to work.