I am new to ASP.NET MVC. I have used PHP before and it was easy to create a session and select user records based on the current session variables.
I have looked everywhere on the Internet for a simple step-by-step tutorial that can show me how to create and use sessions in my C# ASP.NET MVC 4 application. I want to create a session with user variables that I can access from anywhere in my controllers and be able to use the variables in my LINQ queries.
Try
//adding data to session
//assuming the method below will return list of Products
var products=Db.GetProducts();
//Store the products to a session
Session["products"]=products;
//To get what you have stored to a session
var products=Session["products"] as List<Product>;
//to clear the session value
Session["products"]=null;
Due to the stateless nature of the web, sessions are also an extremely useful way of persisting objects across requests by serialising them and storing them in a session.
A perfect use case of this could be if you need to access regular information across your application, to save additional database calls on each request, this data can be stored in an object and unserialised on each request, like so:
Our reusable, serializable object:
[Serializable]
public class UserProfileSessionData
{
public int UserId { get; set; }
public string EmailAddress { get; set; }
public string FullName { get; set; }
}
Use case:
public class LoginController : Controller {
[HttpPost]
public ActionResult Login(LoginModel model)
{
if (ModelState.IsValid)
{
var profileData = new UserProfileSessionData {
UserId = model.UserId,
EmailAddress = model.EmailAddress,
FullName = model.FullName
}
this.Session["UserProfile"] = profileData;
}
}
public ActionResult LoggedInStatusMessage()
{
var profileData = this.Session["UserProfile"] as UserProfileSessionData;
/* From here you could output profileData.FullName to a view and
save yourself unnecessary database calls */
}
}
Once this object has been serialised, we can use it across all controllers without needing to create it or query the database for the data contained within it again.
Inject your session object using Dependency Injection
In a ideal world you would 'program to an interface, not implementation' and inject your serializable session object into your controller using your Inversion of Control container of choice, like so (this example uses StructureMap as it's the one I'm most familiar with).
public class WebsiteRegistry : Registry
{
public WebsiteRegistry()
{
this.For<IUserProfileSessionData>().HybridHttpOrThreadLocalScoped().Use(() => GetUserProfileFromSession());
}
public static IUserProfileSessionData GetUserProfileFromSession()
{
var session = HttpContext.Current.Session;
if (session["UserProfile"] != null)
{
return session["UserProfile"] as IUserProfileSessionData;
}
/* Create new empty session object */
session["UserProfile"] = new UserProfileSessionData();
return session["UserProfile"] as IUserProfileSessionData;
}
}
You would then register this in your Global.asax.cs file.
For those that aren't familiar with injecting session objects, you can find a more in-depth blog post about the subject here.
A word of warning:
It's worth noting that sessions should be kept to a minimum, large sessions can start to cause performance issues.
It's also recommended to not store any sensitive data in them (passwords, etc).
This is how session state works in ASP.NET and ASP.NET MVC:
ASP.NET Session State Overview
Basically, you do this to store a value in the Session object:
Session["FirstName"] = FirstNameTextBox.Text;
To retrieve the value:
var firstName = Session["FirstName"];
You can store any kind of data in a session using:
Session["VariableName"]=value;
This variable will last 20 mins or so.
U can store any value in session like
Session["FirstName"] = FirstNameTextBox.Text;
but i will suggest u to take as static field in model assign value to it and u can access that field value any where in application. U don't need session. session should be avoided.
public class Employee
{
public int UserId { get; set; }
public string EmailAddress { get; set; }
public static string FullName { get; set; }
}
on controller - Employee.FullName = "ABC";
Now u can access this full Name anywhere in application.
Related
I am developing a web application in ASP.NET MVC5.
Like all basic web applications it also has a login page where a user can authenticate himself. Once authenticated I want to store a couple of user-related items in the Session so I don't have to query the database every time to reconstruct the authenticated user.
After having read Mark Seemann's book about Dependency Injection I want to loosely couple all my layers and make sure that everything can easily be replaced.
At the moment my SessionProvider is by default using the Session object, but maybe in the future this could change to another type of storage mechanism.
The approach I have taken is by using Ambient Context which he explained with the TimeProvider example, but I am wondering if this is the right approach for this functionality and if it is thread safe (also for unit testing).
Is my solution proper or how would you implement such a mechanism? This has been in my head for days now so who can help me define the best solution?
Thanks!
public abstract class SessionProvider
{
private static SessionProvider _current;
static SessionProvider()
{
_current = new DefaultSessionProvider();
}
public static SessionProvider Current
{
get { return _current; }
set
{
if (value == null)
{
throw new ArgumentNullException();
}
_current = value;
}
}
public abstract string UserName { get; set; }
}
My local default:
public class DefaultSessionProvider : SessionProvider
{
public override string UserName
{
get { return (string) HttpContext.Current.Session["username"]; }
set { HttpContext.Current.Session["username"] = value; }
}
}
So I have access in my entire solution to my SessionProvider, whether this is a real session object or a database-driven storage mechanism...
SessionProvider.Current.UserName = "myUserName";
Once authenticated I want to store a couple of user-related items in
the Session so I don't have to query the database every time to
reconstruct the authenticated user.
Well, it looks like you're working on some sort of caching mechanism. It doesn't really matter if it's in a Session or in Redis cache, or any other type of cache. And this cache is key-value storage. I would create cache interface, something like that:
interface ICache
{
object this[string key] {get; set;}
}
And create concrete classes. SessionCache in your case:
public SessionCache : ICache
{
private IHttpSessionState _session;
public SessionCache(IHttpSessionState session)
{
_session = session;
}
// ICache implementation goes here...
}
So you'll narrow down the problem to dependency-inject Session object to concrete class (SessionCache). With Ninject you can do something like:
.WithConstructorArgument("session",ninjectContext=>HttpContext.Session);
And after that you can finally make your controllers dependent on ICache.
In your unit tests project you can create another ICache concrete class, something like DummyCache with in-memory cache. So you can test your controllers without sticking to Session object.
I have created a web service with ServiceStack which returns List<SyncUserDTO>.
It has more properties, but I simplified it to one field, Timestamp.
[DataContract]
public class SyncUserDTO
{
public SyncUserDTO()
{
Timestamp = new TimestampDTO();
}
[DataMember(Order = 1)]
public TimestampDTO Timestamp { get; set; }
}
[DataContract]
public class TimestampDTO
{
[DataMember]
public bool DataValid { get; set; }
[DataMember]
public DateTime? Value { get; set; }
}
The service seems to work perfectly (with other tests), but when I create a client console application and Add Service Reference, the SyncUserDTO does not have the constructor, meaning this doesn't work:
static void SendUsersServiceReference()
{
var users = new List<SyncUserDTO>();
for (var i = 0; i < 5; i++)
{
var user = new SyncUserDTO();
user.Timestamp.Value = DateTime.Now; // NullReferenceException,
user.Timestamp.DataValid = true; // as Timestamp is null
}
}
When pressing F12 on SyncUserDTO, I can't seem to find any Constructor method in Reference.cs, explaining why the above doesn't work.
But why is the constructor not created in my proxy classes in the client application?
I need to do the "construction" myself in the client, and then it works:
var user = new SyncUserDTO() { Timestamp = new TimestampDTO() };
Of cause, I don't want the people who consumes my service to have to create this themselves. They should really note care about the underlying TimestampDTO. The constructor should do this.
Btw, I searched Google and SO for terms like "Constructor not created in proxy class with Add Service Reference" with and without "ServiceStack", no results to aid me in this quest...
Pps. Demis (ServiceStack), if you're reading this, yes SOAP is on the way out, REST is the new black - but I want to support both, which it seems like ServiceStack does, which is really great. I love ServiceStack :D
try to instanciate your property by the time you are going to access it, I know that´s a workaround but it could be convenient in your scenario.
private TimestampDTO _timestamp;
public TimestampDTO Timestamp
{
get
{
if(_timestamp==null) _timestamp=new TimestampDTO();
return _timestamp;
}
set
{
_Timestamp=value;
}
}
This is my solution (for now):
I created a new service method in my service, where the client gets a new UserDTO complete with all fields. This way, the constructor is run on the server. I bet I have quite a performance hit this way, but it doesn't matter that much (now...).
Service DTO's:
[DataContract]
public class ReturnNewEmptyUser : IReturn<ReturnNewEmptyUserResponse> {}
[DataContract]
public class ReturnNewEmptyUserResponse
{
[DataMember]
public SyncUserDTO User { get; set; }
}
The Service:
public class SyncService : Service
{
public ReturnNewEmptyUserResponse Any(ReturnNewEmptyUser request)
{
var user = new ReturnNewEmptyUserResponse { User = new SyncUserDTO() };
return user;
}
}
On the client:
static void SendUsersServiceReference()
{
var webservice = new ServiceReference1.SyncReplyClient();
var users = new List<User>();
for (var i = 0; i < 5; i++)
{
var userResponse = webservice.ReturnNewEmptyUser(new ReturnNewEmptyUser());
var user = userResponse.User;
user.Timestamp.Value = DateTime.Now;
user.Timestamp.DataValid = true;
// Continue with field population...
users.Add(user);
}
// Send users with webservice method
// ...
}
We're wondering if it is a bad way to expose the fields this way. It is nice, because the client can use autocomplete and know exactly the types used - but is it better to force the client to create an XML/JSON in a specific format.
This should be in another question - this question I guess has been answered: Add service reference/proxy classes does not contain methods (incl. constructors for types), only types. If you really need the constructor, have it run and then exposed on the server and then consume it from the client. Like a factory-thing, as Adam wrote here: Class constructor (from C# web service) won't auto-implement properties in C# MVC
Btw - is there any security issues with this design? User is logged in via url-credentials (should probably be header authentication), only a few systems has access to it.
A proxy class does not keep implementation details, like a constructor. It is just a DTO. This can only be done if you share the classes, through a shared project.
Think about that servicestack is just telling the client which properties it needs, and their type.. the implementation is up to the client.
I work on an ASP.NET MVC4 solution. When the user is logged in, I would like to display his fullname (not the username provided in the login form). His fullname (firstname + lastname actually stored in the user table in my database) should be displayed in the top right corner.
For better performance, I don't want to query the database each time a request is done.
How to proceed?
Keeping the user information (firstname, lastname, ...) in a cookie?
Keeping the user information is a session variable for all the lifecycle of the application?
Keeping the user information in a 'Profile' like explained here: How to assign Profile values? (*)
Something else?
(*) I think this solution a little complex for the use I have.
Thanks.
I would use a cookie. It doesn't hog up any memory on your machine like Session, and it doesn't hit the database like Profile would. Just remember to delete the cookie when the user signs off.
Note that the Profile would hit the database server each time you make a request. As far as I know, Profile data is not cached anywhere on the web server (unless you have a custom profile provider).
Another reason why I like cookie: if you ever want to store any additional user information for fast access, like UserPrimaryKey, or any special user preferences, you can just store them as JSON in the cookie. Here is an example:
Another note: the code below uses Newtonsoft.Json (the JsonConvert lines). It should come out of the box in an MVC4 project, but for an MVC3 project, you can just add it via nuget.
public class UserCacheModel
{
public string FullName { get; set; }
public string Preference1 { get; set; }
public int Preference2 { get; set; }
public bool PreferenceN { get; set; }
}
public static class UserCacheExtensions
{
private const string CookieName = "UserCache";
// put the info in a cookie
public static void UserCache(this HttpResponseBase response, UserCacheModel info)
{
// serialize model to json
var json = JsonConvert.SerializeObject(info);
// create a cookie
var cookie = new HttpCookie(CookieName, json)
{
// I **think** if you omit this property, it will tell the browser
// to delete the cookie when the user closes the browser window
Expires = DateTime.UtcNow.AddDays(60),
};
// write the cookie
response.SetCookie(cookie);
}
// get the info from cookie
public static UserCacheModel UserCache(this HttpRequestBase request)
{
// default user cache is empty
var json = "{}";
// try to get user cache json from cookie
var cookie = request.Cookies.Get(CookieName);
if (cookie != null)
json = cookie.Value ?? json;
// deserialize & return the user cache info from json
var userCache = JsonConvert.DeserializeObject<UserCacheModel>(json);
return userCache;
}
}
With this, you can read / write the cookie info from a controller like this:
// set the info
public ActionResult MyAction()
{
var fullName = MethodToGetFullName();
var userCache = new UserCache { FullName = fullName };
Response.UserCache(userCache);
return Redirect... // you must redirect to set the cookie
}
// get the info
public ActionResult MyOtherAction()
{
var userCache = Request.UserCache();
ViewBag.FullName = userCache.FullName;
return View();
}
I have built a simple MVC3-based ticket entry site for a less-than-usable call center application and am attempting to refactor my prototype to better adhere to design patterns partly to make it more maintainable going forward but mostly as a learning exercise.
The user-facing view is a form consisting of basic user information in addition to a few panels allowing selection of various resource types. Each resource type (hardware, software, etc) is displayed in the same way: using dual, filterable listboxes with add/remove buttons, an optional “justification” textarea that conditionally displays if a requested resource requires justification, and general comments.
I have built the following ViewModel for the individual panels:
public class RequestableList
{
// list of requestable items ids requiring justification
private List<string> _restrictedItems = new List<string>();
public List<string> RestrictedItems
{
get { return _restrictedItems; }
set { _restrictedItems = value; }
}
// the key-value pairs from which to populate available items list
private Dictionary<string, string> _availableItems = new Dictionary<string, string>();
public Dictionary<string, string> AvailableItems
{
get { return _availableItems; }
set { _availableItems = value; }
}
// item ids requested by user
private List<string> _requestedItems = new List<string>();
public List<string> RequestedItems
{
get { return _requestedItems; }
set { _requestedItems = value; }
}
}
The main ViewModel is then comprised of multiple RequestableLists as necessary:
public class SimpleRequestViewModel
{
public UserInfo userInfo { get; set; }
public RequestableList Software {get;set;}
public RequestableList Hardware {get;set;}
public RequestableList Access {get;set;}
public string SoftwareAdditionalInfo { get; set; }
public string HardwareAdditionalInfo { get; set; }
public string AccessFileMailShare { get; set; }
public string AccessAdditionalInfo { get; set; }
public string SoftwareJustification { get; set; }
public string HardwareJustification { get; set; }
public string AccessJustification { get; set; }
public string Comment { get; set; }
}
I have created a strongly typed view for SimpleRequestViewModel (and its variant) and a strongly typed EditorTemplate for RequestableList that wires up the dual listboxes, filtering, and jquery. All renders well and is working but the code currently smells.
When posting to the controller, if the model is valid I must translate it into a readable text description in order to create a new ticket in in the call center app. It doesn’t feel right to have the controller performing that translation into readable text but I run into hurdles when trying to design another class to translate the viewmodels.
Only the selected item values are posted so before translating the request into text I must first lookup the appropriate text for the provided values (they are required in description). The controller is currently the only object that has access to the call center data model for this lookup query.
There are 2 similar ViewModels containing varying combinations of RequestableLists so any translator must be able to translate the various combinations. One has only Hardware and Software, another may have Hardware Software, and a few more RequestableLists.
I considered overriding ToString() directly in the ViewModel but didn’t like that business logic (conditional rendering) there, and again, once posted, the ViewModel doesn’t contain the text for the selected items in the listbox so it would need access to the data model.
The translation of posted values to text as it is currently handled in the controller smells as it’s handled in a switch statement. The controller takes each posted RequestableList and populates the original “Available” fields before it builds the new ticket description.
switch (requestCategory)
{
case RequestableCategory.Software:
itemList = sde.GetSoftware();
break;
case RequestableCategory.Hardware:
itemList = sde.GetHardware();
break;
case RequestableCategory.Access:
itemList = sde.GetAccess();
break;
case RequestableCategory.Telecom:
itemList = sde.GetTelecom();
break;
default:
throw new ArgumentException();
}
So, my question(s):
What patterns are techniques would you recommend for performing the posted viewmodel to ticket description translation?
How do you typically handle the “only posts value” issue with select boxes when you need the text as well as the value?
Is there a better way for me to be approaching this problem?
Again, I am hoping this is a learning experience for me and am more than willing to provide additional information or description if needed.
A few suggestions:
Abstract the logic that does the call center submission into its own class. Provide (from the controller) whatever dependencies it needs to access the call center DB. Have different methods to handle the various types of view models using overloading. Presumably the descriptions come from the DB so you can extract the description from the DB based on the value in this class. This class could also take responsibility for building your view models for the display actions as well. Note that with this pattern the class can interact with the DB directly, through a repository, or even via web services/an API.
Use a repository pattern that implements some caching if performance is an issue in looking up the description from the DB the second time. I suspect it won't be unless your call center is very large, but that would be the place to optimize the query logic. The repository can be the thing that the controller passes to the submission class.
If you don't need to access the DB directly in the controller, consider passing the broker class as a dependency directly.
It might look like:
private ICallCenterBroker CallCenterBroker { get; set; }
public RequestController( ICallCenterBroker broker )
{
this.CallCenterBroker = broker;
// if not using DI, instantiate a new one
// this.CallCenterBroker = broker ?? new CallCenterBroker( new CallCenterRepository() );
}
[HttpGet]
public ActionResult CreateSimple()
{
var model = this.CallCenterBroker.CreateSimpleModel( this.User.Identity.Name );
return View( model );
}
[HttpPost]
public ActionResult CreateSimple( SimpleRequestViewModel request )
{
if (Model.IsValid)
{
var ticket = this.CallCenterBroker.CreateTicket( request );
// do something with ticket, perhaps create a different model for display?
this.CallCenterBroker.SubmitTicket( ticket );
return RedirectToAction( "index" ); // list all requests?
}
return View();
}
I am writing a web application that will allow a user to browse to multiple web pages within the website making certain requests. All information that the user inputs will be stored in an object that I created. The problem is that I need this object to be accessed from any part of the website and I don't really know the best way to accomplish this. I know that one solution is to use session variables but I don't know how to use them in asp .net MVC. And where would I declare a session variable? Is there any other way?
I would think you'll want to think about if things really belong in a session state. This is something I find myself doing every now and then and it's a nice strongly typed approach to the whole thing but you should be careful when putting things in the session context. Not everything should be there just because it belongs to some user.
in global.asax hook the OnSessionStart event
void OnSessionStart(...)
{
HttpContext.Current.Session.Add("__MySessionObject", new MySessionObject());
}
From anywhere in code where the HttpContext.Current property != null you can retrive that object. I do this with an extension method.
public static MySessionObject GetMySessionObject(this HttpContext current)
{
return current != null ? (MySessionObject)current.Session["__MySessionObject"] : null;
}
This way you can in code
void OnLoad(...)
{
var sessionObj = HttpContext.Current.GetMySessionObject();
// do something with 'sessionObj'
}
The answer here is correct, I however struggled to implement it in an ASP.NET MVC 3 app. I wanted to access a Session object in a controller and couldn't figure out why I kept on getting a "Instance not set to an instance of an Object error". What I noticed is that in a controller when I tried to access the session by doing the following, I kept on getting that error. This is due to the fact that this.HttpContext is part of the Controller object.
this.Session["blah"]
// or
this.HttpContext.Session["blah"]
However, what I wanted was the HttpContext that's part of the System.Web namespace because this is the one the Answer above suggests to use in Global.asax.cs. So I had to explicitly do the following:
System.Web.HttpContext.Current.Session["blah"]
this helped me, not sure if I did anything that isn't M.O. around here, but I hope it helps someone!
Because I dislike seeing "HTTPContext.Current.Session" about the place, I use a singleton pattern to access session variables, it gives you an easy to access strongly typed bag of data.
[Serializable]
public sealed class SessionSingleton
{
#region Singleton
private const string SESSION_SINGLETON_NAME = "Singleton_502E69E5-668B-E011-951F-00155DF26207";
private SessionSingleton()
{
}
public static SessionSingleton Current
{
get
{
if ( HttpContext.Current.Session[SESSION_SINGLETON_NAME] == null )
{
HttpContext.Current.Session[SESSION_SINGLETON_NAME] = new SessionSingleton();
}
return HttpContext.Current.Session[SESSION_SINGLETON_NAME] as SessionSingleton;
}
}
#endregion
public string SessionVariable { get; set; }
public string SessionVariable2 { get; set; }
// ...
then you can access your data from anywhere:
SessionSingleton.Current.SessionVariable = "Hello, World!";
Well, IMHO..
never reference a Session inside your view/master page
minimize your useage of Session. MVC provides TempData obj for this, which is basically a Session that lives for a single trip to the server.
With regards to #1, I have a strongly typed Master View which has a property to access whatever the Session object represents....in my instance the stongly typed Master View is generic which gives me some flexibility with regards to strongly typed View Pages
ViewMasterPage<AdminViewModel>
AdminViewModel
{
SomeImportantObjectThatWasInSession ImportantObject
}
AdminViewModel<TModel> : AdminViewModel where TModel : class
{
TModel Content
}
and then...
ViewPage<AdminViewModel<U>>
If you are using asp.net mvc, here is a simple way to access the session.
From a Controller:
{Controller}.ControllerContext.HttpContext.Session["{name}"]
From a View:
<%=Session["{name}"] %>
This is definitely not the best way to access your session variables, but it is a direct route. So use it with caution (preferably during rapid prototyping), and use a Wrapper/Container and OnSessionStart when it becomes appropriate.
HTH
Although I don't know about asp.net mvc, but this is what we should do in a normal .net website. It should work for asp.net mvc also.
YourSessionClass obj=Session["key"] as YourSessionClass;
if(obj==null){
obj=new YourSessionClass();
Session["key"]=obj;
}
You would put this inside a method for easy access.
HTH
There are 3 ways to do it.
You can directly access HttpContext.Current.Session
You can Mock HttpContextBase
Create a extension method for HttpContextBase
I prefer 3rd way.This link is good reference.
Get/Set HttpContext Session Methods in BaseController vs Mocking HttpContextBase to create Get/Set methods
My way of accessing sessions is to write a helper class which encapsulates the various field names and their types. I hope this example helps:
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.SessionState;
namespace dmkp
{
/// <summary>
/// Encapsulates the session state
/// </summary>
public sealed class LoginInfo
{
private HttpSessionState _session;
public LoginInfo(HttpSessionState session)
{
this._session = session;
}
public string Username
{
get { return (this._session["Username"] ?? string.Empty).ToString(); }
set { this._session["Username"] = value; }
}
public string FullName
{
get { return (this._session["FullName"] ?? string.Empty).ToString(); }
set { this._session["FullName"] = value; }
}
public int ID
{
get { return Convert.ToInt32((this._session["UID"] ?? -1)); }
set { this._session["UID"] = value; }
}
public UserAccess AccessLevel
{
get { return (UserAccess)(this._session["AccessLevel"]); }
set { this._session["AccessLevel"] = value; }
}
}
}
Great answers from the guys but I would caution you against always relying on the Session. It is quick and easy to do so, and of course would work but would not be great in all cicrumstances.
For example if you run into a scenario where your hosting doesn't allow session use, or if you are on a web farm, or in the example of a shared SharePoint application.
If you wanted a different solution you could look at using an IOC Container such as Castle Windsor, creating a provider class as a wrapper and then keeping one instance of your class using the per request or session lifestyle depending on your requirements.
The IOC would ensure that the same instance is returned each time.
More complicated yes, if you need a simple solution just use the session.
Here are some implementation examples below out of interest.
Using this method you could create a provider class along the lines of:
public class CustomClassProvider : ICustomClassProvider
{
public CustomClassProvider(CustomClass customClass)
{
CustomClass = customClass;
}
public string CustomClass { get; private set; }
}
And register it something like:
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<ICustomClassProvider>().UsingFactoryMethod(
() => new CustomClassProvider(new CustomClass())).LifestylePerWebRequest());
}
You can use ViewModelBase as base class for all models , this class will take care of pulling data from session
class ViewModelBase
{
public User CurrentUser
{
get { return System.Web.HttpContext.Current.Session["user"] as User };
set
{
System.Web.HttpContext.Current.Session["user"]=value;
}
}
}
You can write a extention method on HttpContextBase to deal with session data
T FromSession<T>(this HttpContextBase context ,string key,Action<T> getFromSource=null)
{
if(context.Session[key]!=null)
{
return (T) context.Session[key];
}
else if(getFromSource!=null)
{
var value = getFromSource();
context.Session[key]=value;
return value;
}
else
return null;
}
Use this like below in controller
User userData = HttpContext.FromSession<User>("userdata",()=> { return user object from service/db });
The second argument is optional it will be used fill session data for that key when value is not present in session.