Is ViewState safe for multiple users in web application - asp.net

In my ASP.Net app i use viewstate to store data of a grid, i use common class for creating viewstate object, like shown below.
public static PageViewState CurrentViewState
{
get
{
if (_app == null)
{
Initialize();
}
return _app;
}
}
/// <summary>
/// Creates new object for singleton class
/// </summary>
private static void Initialize()
{
PageViewState _viewstate = new PageViewState();
_app = _viewstate;
}
/// <summary>
/// Returns viewstate for specified page name
/// </summary>
/// <param name="_page">string : Name of the page</param>
/// <returns></returns>
public object this[string _page]
{
get
{
if (ViewState[_page] != null)
return ViewState[_page];
else
return null;
}
set
{
ViewState[_page] = value;
}
}
I'm using a static property, is it safe when multiple users access this in aspx.cs.
Datatable _dtable = (Datatable)PageViewState.CurrentViewState["MyPage"];
ViewState stores data in client side in the form of hiddenfields so it should be unique for each user, am i right about this.

ViewState stores data in client side and this is safe.

Yes it is as it stores data on the client side i.e. the page user is viewing on his machine.
So you will be seeing the different version of same page(in the sense of viewstate data) and I will be seeing the different version.

ViewState is encrypted string representing the control state and it is at the page level.
This is rendered for each page with the hidden input field.
<input type="hidden" id="__ViewState" value="uxudhk.." />
Each page requested by a different user will have a different hidden field in a page. So this is safe always. In case if your ViewState is modified or altered you will get an Server side error like InValid ViewState.

Related

MiniProfiler MVC SQL Timings Not Displaying

I am using MiniProfiler.Mvc5 v4.2.1 with C# for an ASP.NET MVC5 website. I am implementing MiniProfiler based on the Samples.Mvc5 project included in the source code repo and am having an issue with the display of SQL timings. I am curious if something might be off in my setup, but I am not sure exactly what that might be.
Here is an example of loading the homepage, and I am confused why the SQL timings and percentage all show as 0.0:
However, if I actually click on the sql timings I get this view, which does seem to indicate that each SQL call does have timings associated with it:
The DataConnection class I am using to define ProfileDbConnection and other related objects is in a separate CSPROJ, here are some relevant configuration methods:
/// <summary>
/// Creates a new native connection
/// </summary>
protected override IDbConnection CreateNativeConnection()
{
var connection = new SqlConnection(ConnectionString);
return new ProfiledDbConnection(connection, MiniProfiler.Current);
}
/// <summary>
/// Creates a new SQL command
/// </summary>
/// <param name="cmdText">Command text</param>
protected override DbCommand CreateCommand(string cmdText)
{
var command = new SqlCommand(cmdText, null, (SqlTransaction)Transaction);
return new ProfiledDbCommand(command, (DbConnection)NativeConnection, MiniProfiler.Current);
}
/// <summary>
/// Creates a new command parameter
/// </summary>
/// <param name="name">Parameter name</param>
/// <param name="value">Parameter value</param>
protected override DbParameter CreateParameter(string name, object value)
{
return new SqlParameter(name, value);
}
/// <summary>
/// Creates a data adapter
/// </summary>
protected override DbDataAdapter CreateDataAdapter()
{
return new ProfiledDbDataAdapter(new SqlDataAdapter(), MiniProfiler.Current);
}
In the MVC app's Global.asax.cs:
public MvcApplication()
{
AuthenticateRequest += (sender, e) =>
{
var app = (HttpApplication) sender;
if (Request.IsLocal || app.User != null && app.User.Identity.IsAuthenticated && app.User.Identity.Name == "administrator")
{
MiniProfiler.StartNew();
}
};
EndRequest += (sender, e) =>
{
MiniProfiler.Current?.Stop();
};
}
Can anyone help direct me as to why I might not be seeing them aggregated in the initial view, or where I might start looking to gather more info?
I'm not sure exactly why Mini Profiler would behave like that, as I am not an expert in it. I would, however, wager it's because the Kentico API calls use their own DBContext inside of Kentico, and your DataConnection class does not share the same exact context as Kentico's. The strange thing is that you do see some on the individual level...But it is kinda of hard to tell with out more source code being shared.
But with that being said, Kentico offers automatic integration with Glimpse. Kentico's customized version of Glimpse does show SQL timings and many other profiling options. Check out my blog on how to use that. https://www.mcbeev.com/Blog/January-2018/Why-Kentico-Glimpse-is-a-Must-Have-Tool-for-Kentico-MVC-Developers and a follow up post on adding more memory debugging information at https://www.mcbeev.com/Blog/September-2019/KenticoCacheDoctor-2-Now-With-Kentico-Glimpse.
In the MVC5 world I think Glimpse is still a viable option.

ViewModel instance will always be recreated when switching between pages

I'm using Prism 6, UWP with Unity.
The ViewModels will be automatically injected into the datacontext of the page. However, when I navigate between the pages the viewmodels will always be recreated. Is this behaviour desired by Prism and Unity?
Imagine the following scenario, a user enter some data into a page therefore the proper properties of the viewmodel will be set. When the user is switching back to another page and revisits the page all entered data are lost, because a new viewmodel instance is created.
At the moment my workaround is to override OnNavigatedTo and OnNavigatingFrom to save all properties of the viewmodel with the SessionStateService manual. I'm not sure if this is the correct way?
You can reproduce this behaviour with the following example:
https://github.com/PrismLibrary/Prism-Samples-Windows/tree/master/SplitViewSample/SplitViewSample
I am not using Prism, I'm using modified version of Template 10.
I just had a quick look at the Prism source code. Looks like Template 10 borrowed a lot of ideas from Prism.
I'll try to answer your question from 2 perspectives:
1) AFAIK, in Prism there is a static class with which you can set how to create/resolve you view model when it is automatically looked up for the corresponding View. The class is ViewModelLocationProvider, in file ViewModelLocationProvider.cs you can use following methods to setup the 'view model factories'
/// <summary>
/// Sets the default view model factory.
/// </summary>
/// <param name="viewModelFactory">The view model factory which provides the ViewModel type as a parameter.</param>
public static void SetDefaultViewModelFactory(Func<Type, object> viewModelFactory)
{
_defaultViewModelFactory = viewModelFactory;
}
/// <summary>
/// Sets the default view model factory.
/// </summary>
/// <param name="viewModelFactory">The view model factory that provides the View instance and ViewModel type as parameters.</param>
public static void SetDefaultViewModelFactory(Func<object, Type, object> viewModelFactory)
{
_defaultViewModelFactoryWithViewParameter = viewModelFactory;
}
/// <summary>
/// Registers the view model factory for the specified view type name.
/// </summary>
/// <param name="viewTypeName">The name of the view type.</param>
/// <param name="factory">The viewmodel factory.</param>
public static void Register(string viewTypeName, Func<object> factory)
{
_factories[viewTypeName] = factory;
}
then all the logic for getting view model instance is in the following, pay attention to the comment summary here, it describes the logic/strategy
/// <summary>
/// Automatically looks up the viewmodel that corresponds to the current view, using two strategies:
/// It first looks to see if there is a mapping registered for that view, if not it will fallback to the convention based approach.
/// </summary>
/// <param name="view">The dependency object, typically a view.</param>
/// <param name="setDataContextCallback">The call back to use to create the binding between the View and ViewModel</param>
public static void AutoWireViewModelChanged(object view, Action<object, object> setDataContextCallback)
{
// Try mappings first
object viewModel = GetViewModelForView(view);
// Fallback to convention based
if (viewModel == null)
{
var viewModelType = _defaultViewTypeToViewModelTypeResolver(view.GetType());
if (viewModelType == null)
return;
viewModel = _defaultViewModelFactoryWithViewParameter != null ? _defaultViewModelFactoryWithViewParameter(view, viewModelType) : _defaultViewModelFactory(viewModelType);
}
setDataContextCallback(view, viewModel);
}
on line 87 and 96 you get you view model instance for the corresponding view.
So that means, if you don't call any of those methods to setup the factories, it will fall back to the default factory which is
/// <summary>
/// The default view model factory whic provides the ViewModel type as a parameter.
/// </summary>
static Func<Type, object> _defaultViewModelFactory = type => Activator.CreateInstance(type);
that is pretty clear you will always get a new instance.
Regarding Unity, I didn't see anything special, the only clue is that in the PrismApplication class in PrismApplication.cs, it sets up the factory like following:
/// <summary>
/// Configures the <see cref="ViewModelLocator"/> used by Prism.
/// </summary>
protected virtual void ConfigureViewModelLocator()
{
ViewModelLocationProvider.SetDefaultViewModelFactory((type) => Resolve(type));
}
that means the factory is now using
/// <summary>
/// Resolves the specified type.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>A concrete instance of the specified type.</returns>
protected virtual object Resolve(Type type)
{
return Activator.CreateInstance(type);
}
which you can override with your own implementation.
In PrismUnityApplication class, PrismUnityApplication.cs, it offers a default implementation to resolve the instance with Unity
/// <summary>
/// Implements the Resolves method to be handled by the Unity Container.
/// Use the container to resolve types (e.g. ViewModels and Flyouts)
/// so their dependencies get injected
/// </summary>
/// <param name="type">The type.</param>
/// <returns>A concrete instance of the specified type.</returns>
protected override object Resolve(Type type)
{
return Container.Resolve(type);
}
and yeah, like other guys mentioned, you can control the lifetime of your view models yourself via Unity.
2) sorry for the long answer,
but I feel it's better to show you some code that will make things clear.
I'll keep the 2nd one short.
In my opinion, you don't need a view model when your view is gone.
I am not sure how the Frame stack is implemented in UWP and how they manage the view/page instances. I would assume once you navigate to a different page, the previous view/page should be released or can be released at GC, and you have the parameter and page type to be able to navigate back, but it will be a new instance and you restore the state of your view by restoring your view model.
so really, i think you're on the right track. and you should save/persist your user data whenever you can, and your solution works when the app is suspended and then is resumed, you can still recover the state of your view.
Thanks for reading.
It should be solved when you register your ViewModels as singletons (ContainerControlledLifetimeManager) in the UnityContainer. The best place for this would be the App.xaml.cs in method OnInitializeAsync
protected override Task OnInitializeAsync(IActivatedEventArgs args)
{
Container.RegisterType<MyViewModel>(new ContainerControlledLifetimeManager());
// rest of the method
}

ASP.NET MVC4 Generalized Field Initialization

In ASP.NET MVC4, I want to initialize fields with values. When the user gets the page, before he has posted it back, I want to have it start out with values in some fields. The values will be drawn from the query string, not hard coded. Say a user is filling out a form: He's logged in, you know his name and address. As a courtesy, make those the default values. Doesn't matter where they come from, really, except that it's a set of key-value pairs, and the values are strings. I just want to put something in fields without the user posting the form first and I'd really like to do it without hard-coding a long, long list of assignments to every property in a rather complicated model.
Right now it's done in a JS loop in $(document).ready(), but it belongs on the server. I'd like to replicate that logic, though: Treat the query param names as unique identifiers.
In the Index() method of my controller, I tried calling ModelState.TrySetModelValue() (which when ModelState is populated, identifies each field by one unique string) but at this stage, ModelState is empty, so of course that didn't work. I tried changing Index() to expect an instance of the model as a parameter, but that doesn't help.
Must I rewrite every #Html.EditorFor()/TextBoxFor()/etc. call in the application? That seems crazy. Properly, this is something I'd do in a loop, in one place, not scattered around in multiple spots in each of a growing number of views.
I have a feeling that I'm failing to grasp something fundamental about the way MVC4 is intended to work.
UPDATE 2
It turns out that if you decorate your action method with [HttpGet], and you have it expect the model as a parameter, then if you use the field names (foo.bar) rather than IDs (foo_bar) in the query string, it does what I want automatically. ModelState is populated. I must not have had the action method decorated with [HttpGet] when I looked at ModelState.
If a field is set via query string automatically, that supersedes whatever's in your model. That's reasonable; the whole point is to override the model's default values. But if you want to in turn override possible query string values (e.g., say there's a checkbox for an "electronic signature"; that should always require an explicit effort on the user's part), then you've got to do that via ModelState.
That means that my first solution, below, had no actual effect (provided I had the [HttpGet] property on the action method). It only set properties of the model which had already been set in ModelState by the framework, and whose values in the model were therefore ignored.
What's a little bit stranger is that ModelState gives fields a different key if they're not in the query string. foo.bar.baz uses just that as a key if it's in the query string, but if it isn't, the key becomes foo.footypename.bar.bartypename.baz. There appears to be an exception if the property's name is the same as it's type: I have a Name model class, and another model class has a property public Name Name { get; set }. Properties of type Name, which are named name, are never followed by their type name in the ModelState keys. However, I have not yet ruled out other possible reasons for that particular property having its typename excluded. That's a guess. The typenames are excluded for "leaf" properties in all cases in my model. Is that because they're types known to the system, or "leaves", or what? I don't know.
In any case, a leaf property of the "root" class of the model always uses its own name as a key in ModelState.
So the generalized answer is you assign to the model. But there's a different specific answer for initialization from a query string.
UPDATE
Solution -- much code snipped
// Controller base
public abstract class ControllerBase<TModel> : Controller
{
[HttpGet]
public virtual ActionResult Index(TModel model)
{
HttpContext.Request.QueryString.CopyTo(model);
return View("Index", model);
}
}
public static class Extensions
{
/// <summary>
/// Given NameValueCollection of keys/values in the form
/// "foo.bar.baz" = "text", and an object which is the *parent* of
/// foo, set properties of foo accordingly.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="src"></param>
/// <param name="model"></param>
public static void CopyTo<T>(this NameValueCollection src, T target)
{
String strkey;
Object objval;
foreach (var key in src.Keys)
{
strkey = "" + key;
objval = src[strkey];
target.TrySetPropertyValue(strkey, objval);
}
}
/// <summary>
/// Given a reference to an object objThis, the string "foo.bar.baz",
/// and an object o of a type optimistically hoped to be convertible
/// to that of objThis.foo.bar.baz, set objThis.foo.bar.baz = o
///
/// If foo.bar is null, it must have a default constructor, or we fail
/// and return false.
/// </summary>
/// <param name="objThis"></param>
/// <param name="propPathName"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool TrySetPropertyValue(this object objThis,
string propPathName, object value)
{
if (string.IsNullOrWhiteSpace(propPathName))
{
throw new ArgumentNullException(propPathName);
}
var names = propPathName.Split(new char[] { '.' }).ToList();
var nextPropInfo = objThis.GetType().GetProperty(names.First());
if (null == nextPropInfo)
return false;
if (names.Count > 1)
{
var nextPropValue = nextPropInfo.GetValue(objThis, null);
if (null == nextPropValue)
{
nextPropValue = Activator
.CreateInstance(nextPropInfo.PropertyType);
nextPropInfo.SetValue(objThis, nextPropValue);
}
names.RemoveAt(0);
return nextPropValue.TrySetPropertyValue(
String.Join(".", names), value);
}
else
{
try
{
var conv = System.ComponentModel.TypeDescriptor
.GetConverter(nextPropInfo.PropertyType);
value = conv.ConvertFrom(value);
nextPropInfo.SetValue(objThis, value);
}
catch (System.FormatException)
{
return false;
}
return true;
}
}
}
You can initialize your model in controller with default values and then use it like
#Html.TextBoxFor(m => Model.Name)
Initialization in Controller:
public ActionResult Index()
{
MyModel model = new MyModel();
model.Name = "myname";
return View("myview", model);
}
You can also set the attributes in TextBoxFor
#Html.TextBoxFor(m => Model.Name, new { value = "myname"})
Update
If your url looks like mysite/Edit?id=123 try decalring your controller action like
public ActionResult Edit(string id)
{ ...
Also try decorating it with HttpPost or HttpGet attribute

Revalidate Model When Using WebAPI (TryValidateModel equivalent)

Using vanilla MVC I can revalidate my model with TryValidateModel. The TryValidateModel method doesn't seem to be applicable to WebAPI. How can I revalidate my model when using WebAPI?
I know it has been a while since this has been asked, but the problem is still valid. Thus i thought i should share my solution to this problem.
I decided to implement the TryValidateModel(object model) myself, based on the implementation in the System.Web.Mvc.Controller.cs
The problem is that the mvc's TryValidateModel internally used their own HttpContext and ModelState. If you go and compaire the two, they are very similar....
The be able to use our own HttpContext there exists a HttpContextWrapper that can be used for that.
And Since we have to clear our model state, it doesn't really matter that we use a different type of ModelState , as long as we get the desired result, thus i create a new ModelState object from the correct type...
I did add the error to the ModelState of the controller and not to the model state to the newly created ModelState , This seems to work just fine for me :)
Here is my code, that i just added to the controller...
do not forget to import the library...
using System.Web.ModelBinding;
protected internal bool TryValidateModel(object model)
{
return TryValidateModel(model, null /* prefix */);
}
protected internal bool TryValidateModel(object model, string prefix)
{
if (model == null)
{
throw new ArgumentNullException("model");
}
ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType());
var t = new ModelBindingExecutionContext(new HttpContextWrapper(HttpContext.Current), new System.Web.ModelBinding.ModelStateDictionary());
foreach (ModelValidationResult validationResult in ModelValidator.GetModelValidator(metadata, t).Validate(null))
{
ModelState.AddModelError(validationResult.MemberName, validationResult.Message);
}
return ModelState.IsValid;
}
I don't know when was it added but now there is Validate method on api controller.
ApiController.Validate Method (TEntity)
https://msdn.microsoft.com/en-us/library/dn573258%28v=vs.118%29.aspx
Based from rik-vanmechelen original answer, here is my version that relies on the services container exposed by Web API.
/// <summary>
/// Tries to validate the model.
/// </summary>
/// <param name="model">The model.</param>
/// <returns>Whether the model is valid or not.</returns>
protected internal bool TryValidateModel(object model)
{
if (model == null)
{
throw new ArgumentNullException("model");
}
var metadataProvider = Configuration.Services.GetService<System.Web.Http.Metadata.ModelMetadataProvider>();
var validatorProviders = Configuration.Services.GetServices<System.Web.Http.Validation.ModelValidatorProvider>();
var metadata = metadataProvider.GetMetadataForType(() => model, model.GetType());
ModelState.Clear();
var modelValidators = metadata.GetValidators(validatorProviders);
foreach (var validationResult in modelValidators.SelectMany(v => v.Validate(metadata, null)))
{
ModelState.AddModelError(validationResult.MemberName, validationResult.Message);
}
return ModelState.IsValid;
}
This uses the following simple extension methods to access the services :
/// <summary>
/// Services container extension methods.
/// </summary>
public static class ServicesContainerExtensions
{
/// <summary>
/// Gets the service.
/// </summary>
/// <typeparam name="TService">The type of the service.</typeparam>
/// <param name="services">The services.</param>
/// <returns>The service.</returns>
/// <exception cref="System.ArgumentNullException">services</exception>
public static TService GetService<TService>(this ServicesContainer services)
{
if (services == null)
{
throw new ArgumentNullException("services");
}
return (TService)((object)services.GetService(typeof(TService)));
}
/// <summary>
/// Gets the services.
/// </summary>
/// <typeparam name="TService">The type of the service.</typeparam>
/// <param name="services">The services.</param>
/// <returns>The services.</returns>
/// <exception cref="System.ArgumentNullException">services</exception>
public static IEnumerable<TService> GetServices<TService>(this ServicesContainer services)
{
if (services == null)
{
throw new ArgumentNullException("services");
}
return services.GetServices(typeof(TService)).Cast<TService>();
}
}
The advantage of using this method is that it reuses the MetadataProvider and ValidatorProvider(s) you have configured for your Web API application while the previous answer is retrieving the one configured in ASP.NET MVC.
ASP.NET MVC and WebAPI run through different pipelines.
Turns out TryValidateModel is not supported in WebAPI. There's a feature request over on CodePlex.

Is there a way to use use a cache profile when manually adding items to the cache?

I have output caching in my application configured using output cache profiles in the web.config. It is very convenient to be able to setup caching on all the output items that need it and then be able to adjust all the cache settings in one place.
However, I am also implementing caching in my data and logic layers for certain items. It would be convenient if I could also reference a profile instead of hard coding the caching parameters for data and logic items I want to cache, but there doesn't seem to be a way to reference a profile in the Insert() method on the cache object.
Alternativly, I could build my own configuration section to list cache profiles for manually added items.
You can get a list of your output cache profiles doing this:
private Dictionary<string, OutputCacheProfile> _outputCacheProfiles;
/// <summary>
/// Initializes <see cref="OutputCacheProfiles"/> using the settings found in
/// "system.web\caching\outputCacheSettings"
/// </summary>
void InitializeOutputCacheProfiles(
System.Configuration.Configuration appConfig,
NameValueCollection providerConfig)
{
_outputCacheProfiles = new Dictionary<string, OutputCacheProfile>();
OutputCacheSettingsSection outputCacheSettings =
(OutputCacheSettingsSection)appConfig.GetSection("system.web/caching/outputCacheSettings");
if(outputCacheSettings != null)
{
foreach(OutputCacheProfile profile in outputCacheSettings.OutputCacheProfiles)
{
_outputCacheProfiles[profile.Name] = profile;
}
}
}
And then use it on your insert:
/// <summary>
/// Gets the output cache profile with the specified name
/// </summary>
public OutputCacheProfile GetOutputCacheProfile(string name)
{
if(!_outputCacheProfiles.ContainsKey(name))
{
throw new ArgumentException(String.Format("The output cache profile '{0}' is not registered", name));
}
return _outputCacheProfiles[name];
}
/// <summary>
/// Inserts the key/value pair using the specifications of the output cache profile
/// </summary>
public void InsertItemUsing(string outputCacheProfileName, string key, object value)
{
OutputCacheProfile profile = GetOutputCacheProfile(outputCacheProfileName);
//Get settings from profile to use on your insert instead of hard coding them
}
If you are referring to C#'s Cache.Insert object you can append a GUID to the key so that every profile has a corresponding GUID which you can extract out of the cache when you want to retrieve the profile later on.

Resources