ASP.NET MVC Session usage - asp.net-mvc

Currently I am using ViewData or TempData for object persistance in my ASP.NET MVC application.
However in a few cases where I am storing objects into ViewData through my base controller class, I am hitting the database on every request (when ViewData["whatever"] == null).
It would be good to persist these into something with a longer lifespan, namely session. Similarly in an order processing pipeline, I don't want things like Order to be saved to the database on creation. I would rather populate the object in memory and then when the order gets to a certain state, save it.
So it would seem that session is the best place for this? Or would you recommend that in the case of order, to retrieve the order from the database on each request, rather than using session?
Thoughts, suggestions appreciated.
Thanks
Ben

Just thought I would share how I am using session in my application. I really like this implementation (Suggestions for Accessing ASP.NET MVC Session[] Data in Controllers and Extension Methods?) of using session as it makes it easy to swap out session for another store or for testing purposes.
Looking at the implementation it reminded me of the ObjectStore I have used in other projects to serialize objects as binary or xml and store in a database or on the filesystem.
I therefore simplified my interface (previously T had to be a class) and came up with the following:
public interface IObjectStore {
void Delete(string key);
T Get<T>(string key);
void Store<T>(string key, T value);
IList<T> GetList<T>(string key);
}
And my session store implementation:
public class SessionStore : IObjectStore
{
public void Delete(string key) {
HttpContext.Current.Session.Remove(key);
}
public T Get<T>(string key) {
return (T)HttpContext.Current.Session[key];
}
public void Store<T>(string key, T value) {
HttpContext.Current.Session[key] = value;
}
public IList<T> GetList<T>(string key) {
throw new NotImplementedException();
}
}
I then take in an IObjectStore in my base controller's constructor and can then use it like so to expose properties to my other controllers:
public string CurrentCustomer {
get {
string currentCustomer =
sessionStore.Get<string>(SessionKeys.CustomerSessionKey);
if (currentCustomer == null) {
currentCustomer = Guid.NewGuid().ToString();
sessionStore.Store<string>(SessionKeys.CustomerSessionKey, currentCustomer);
}
return currentCustomer;
}
}
Am quite pleased with this approach.

I believe this is what Session was designed for - to temporarily store session specific data.
However, due to increased complexity connected with using the Session, even if negligible - in my own ASP.NET MVC project, I have decided to hit the database on every Order creation step page (only ID is passed between the steps). I am ready to optimize and start using session as soon as I will see that the extra database hit for every request is a performance bottleneck.

You can serialize what you wish to persist and place it in a hidden input field like ViewState in WebForms.
Here's an article that should get you started: http://weblogs.asp.net/shijuvarghese/archive/2010/03/06/persisting-model-state-in-asp-net-mvc-using-html-serialize.aspx

Related

Entity Framework Core 1.0 unit of work with Asp.Net Core middleware or Mvc filter

I am using EF Core 1.0 (previously known ad EF7) and ASP.NET Core 1.0 (previously known as ASP.NET 5) for a RESTful API.
I'd like to have some unit of work scoped to an http request in such a way that when responding to the HTTP request either ALL the changes made to the DbContext will be saved onto the database, or none will be saved (if there was some exception, for example).
In the past I have used WebAPI2 for this purpose with NHibernate by using an Action filter where I begin the transaction on action executing, and on action executed I end the transaction and close the session. This was the way recommended at http://isbn.directory/book/9781484201107
However now I am using Asp.Net Core (with Asp.Net Core Mvc although this should not be relevant) and Entity Framework which, I understood, already implements a unit of work.
I think having a middleware plugged into the ASP.NET pipeline (before MVC) would be the right way to do things. So a request would go:
PIPELINE ASP.NET: MyUnitOfWorkMiddleware ==> MVC Controller ==> Repository ==> MVC Controller ==> MyUnitOfWorkMiddleware
I was thinking of having this middleware save the DbContext changes if no exception happened, so that in my repository implementations I don't even need to do dbcontext.SaveChanges() and everything would be like a centralized transaction. In pseudocode I guess it would be something like:
class MyUnitOfWorkMiddleware
{
//..
1-get an instance of DbContext for this request.
try {
2-await the next item in the pipeline.
3-dbContext.SaveChanges();
}
catch (Exception e) {
2.1-rollback changes (simply by ignoring context)
2.2-return an http error response
}
}
Does this make sense? Does anybody have any example of something similar? I can't find any good practice or recommendation around this.
Also, if I go with this approach at my MVC controller level I would not have access to any resource ID created by the database when POSTing a new resource because the ID would not be generated until the dbContext changes are saved (later on in the pipeline in my middleware AFTER the controller has finished executing). What if I needed to access the newly created ID of a resource in my controller?
Any advice would be greatly appreciated!
UPDATE 1: I found a problem with my approach to use middleware to achieve this because the DbContext instance in the middleware is not the same as during the MVC (and repositories) lifetime. See the question Entity Framework Core 1.0 DbContext not scoped to http request
UPDATE 2:I haven't yet found a good solution. Basically these are my options so far:
Save the changes in DB as soon as possible. That means saving it on the repository implementation itself. The problem with this approach is that for an Http request maybe I want to use several repositories (i.e: save something in database and then upload a blob to a cloud storage) and in order to have a Unit of Work I would have to implement a repository that deals with more than one entity or even more than one persistance method (DB and Blob Storage), which defeats the whole purpose
Implement an Action Filter where I wrap the whole action execution in a DB transaction. At the end of the controller's action execution, if there are no exceptions I commit chanches to DB but if there are exceptions I rollback and discard the context. The problem with this is that my controller's action may need a generated Entity's Id in order to return it to the http client (i.e: If I get a POST /api/cars I would like to return a 201 Accepted with a location header that identifies the new resource created at /api/cars/123 and the Id 123 would not be available yet since the entity has not been saved in DB and the Id is still a temporary 0). Example in controller's action for a POST verb request:
return CreatedAtRoute("GetCarById", new { carId= carSummaryCreated.Id }, carSummaryCreated); //carSummaryCreated.Id would be 0 until the changes are saved in DB
How could I have the whole controller's action wrapped in a DB transaction and at the same time have available any Id generated by the database in order to return it in the Http Response from the controller? Or.. is there any elegant way to overwrite the http response and set the Id at the action filter level once the DB changes have been commited?
UPDATE 3: As per nathanaldensr's comment I could get the best of both worlds (wrapping my controller's action execution in a DB transaction _ UoW and also knowing the Id of the new resource created even before the DB commits changes) by using code generated Guids instead relying on database to generate the Guid.
As per Entity Framework Core 1.0 DbContext not scoped to http request
I could not use a middleware to achieve this because the instance of DbContext that the middleware gets injected is not the same as the DbContext during MVC execution (in my controllers, or repositories).
I had to go with a similar approach to save the changes in DbContext after the controller's action execution using a Global Filter.
There is no official documentation yet about filters in MVC 6 so if anybody is interested on this solution see below the filter and the way I make this filter global so that it executes before any controller's action.
public class UnitOfWorkFilter : ActionFilterAttribute
{
private readonly MyDbContext _dbContext;
private readonly ILogger _logger;
public UnitOfWorkFilter(MyDbContext dbContext, ILoggerFactory loggerFactory)
{
_dbContext = dbContext;
_logger = loggerFactory.CreateLogger<UnitOfWorkFilter>();
}
public override async Task OnActionExecutionAsync(ActionExecutingContext executingContext, ActionExecutionDelegate next)
{
var executedContext = await next.Invoke(); //to wait until the controller's action finalizes in case there was an error
if (executedContext.Exception == null)
{
_logger.LogInformation("Saving changes for unit of work");
await _dbContext.SaveChangesAsync();
}
else
{
_logger.LogInformation("Avoid to save changes for unit of work due an exception");
}
}
}
and the filter gets plugged into my MVC at Startup.cs when configuring MVC.
public void ConfigureServices(IServiceCollection services)
{
//..
//Entity Framework 7
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<SpeediCargoDbContext>(options => {
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]);
});
//MVC 6
services.AddMvc(setup =>
{
setup.Filters.AddService(typeof(UnitOfWorkFilter));
});
//..
}
This still leaves a question (see UPDATE 2 on my question). What if I want my controller to respond to an http POST request with a 201 Accepted with a Location header that includes the Id of the entity created in DB? When the controller's action finalises execution the changes have not yet been committed to DB therefore the Id of the entity created is still 0 until the action filter saves changes and the DB generates a value.
I am also facing the same issue and not sure which approach to follow.
One of the approach that I used is as follow:
public class UnitOfWorkFilter : ActionFilterAttribute
{
private readonly AppDbContext _dbContext;
public UnitOfWorkFilter(AppDbContext dbContext,)
{
_dbContext = dbContext;
}
public override void OnActionExecuted(ActionExecutedContext context)
{
if (!context.HttpContext.Request.Method.Equals("Post", StringComparison.OrdinalIgnoreCase))
return;
if (context.Exception == null && context.ModelState.IsValid)
{
_dbContext.Database.CommitTransaction();
}
else
{
_dbContext.Database.RollbackTransaction();
}
}
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.HttpContext.Request.Method.Equals("Post", StringComparison.OrdinalIgnoreCase))
return;
_dbContext.Database.BeginTransaction();
}
}
My advice, use dbContext.SaveChanges() in the controller as it is demonstrated in all examples over the web. What you want to do sounds quite fancy and could backfire as you guessed at the end of your post. And IMO, it doesn't make sense.
Regarding your second question/task:
....when responding to the HTTP request either ALL the changes made to the DbContext will be saved onto the database, or none will be saved (if there was some exception, for example).
I think you need something like 'transaction-per-request'. It is just an idea, haven't tested it at all. I just put the code together in this sample middleware:
public class TransactionPerRequestMiddleware
{
private readonly RequestDelegate next_;
public TransactionPerRequestMiddleware(RequestDelegate next)
{
next_ = next;
}
public async Task Invoke(HttpContext context, DbContext dbContext)
{
var transaction = dbContext.Database.BeginTransaction(
System.Data.IsolationLevel.ReadCommitted);
await next_.Invoke(context);
if (context.Response.StatusCode == 200)
{
transaction.Commit();
}
else
{
transaction.Rollback();
}
}
}
Good luck

DbContext lifetime beginning after user login

Typically DbContext and ConnectionString are set at application start. In my ASP.NET MVC application I have a database with Users and ConnectionStrings data and depending on which user logs in, I want to use their ConnectionString to connect them to a secondary DbContext.
I tried to use DbContextScope but with the current implementation it doesn't seem to support this scenario. (I posted a related question for that here).
So in lifecycle of an ASP.NET MVC application how can we make sure the secondary DbContext is instantiated only after the user is logged in? What's the correct way to manage the lifecycle of DbContext here.
Thanks!
There is an overload for DbContext that takes in the connection string. With this, you could add a constructor to pass in the secondary connection string based upon the user that is accessing data.
public MySecondaryDbContext(string connectionString)
: base(connectionString)
{
}
Alternatively, you could pass in a user object that has the connection string to use.
public MySecondaryDbContext(UserObject user)
: base(user.ConnectionString)
{
}
Hope this helps you out.
Update for Lifecycle
As to the lifecycle, you could use something like this with a null check from the calling side.
public static MySecondaryDbContext GetContextForUser(UserObject user)
{
if(user.IsLoggedIn)
return null;
return new MySecondaryDbContext(user.ConnectionString);
}
private MySecondaryDbContext(string connectionString)
: base(connectionString)
{
}
This will prevent the secondary DbContext from being instantiated prior to the user being logged in.

Properly using C# lock in web application

I have a helper class which reads a big XML document and generates a list of c# objects.
I work with these objects quite a lot, so i thought the best way of doing this would be to save them in memory and then access them from there.
I made a simple repository, which gets an object from memory, and if doesn't exists, it adds it.
The Repository looks like this:
public class XmlDocumentRepository
{
private readonly ICacheStorage _cacheStorage;
public XmlDocumentRepository(ICacheStorage cacheStorage)
{
_cacheStorage = cacheStorage;
}
private readonly object _locker = new object();
private void DeserializeXmlDocument()
{
lock (_locker)
{
// I deserialize the xml document, i generate the c# classes, and save them in cache
IEnumerable<Page> pages = new XmlDeserializerHelper().DeserializeXml();
foreach(var page in pages)
{
_cacheStorage.Add(page_Id, page);
}
}
}
public Page GetPage(Guid page_Id)
{
Page page = _cacheStorage.Get<Page>(page_Id);
if (page != null)
return page;
lock (_locker)
{
page = _cacheStorage.Get<Page>(page_Id);
if (page != null)
return page;
DeserializeXmlDocument();
page = _cacheStorage.Get<Page>(page_Id);
return page;
}
}
}
The XmlDocumentRepository is used inside a web application (asp.net mvc more exacly).
Is the implementation of the repository good? I am using the lock statements properly?
In my comments on the question I misunderstood the cache being shared. I think you will need to do one of the following options:
Make XmlDocumentRepository a singleton which is used across all requests because the lock object is a private field so each request will have a new instance of the repository with a new field.
Make the lock object a static field so that it is shared across all XmlDocumentRepository instances.
As a primary rule, you want to protect all access variations to data stores that are used by multiple threads. I see several potential problems with your implementation;
1: ICacheStorage is provided from the outside, which means that this collection could be modified elsewhere, which may or may not be protected by locks. Maybe you should require that the collection itself uses locking internally, or other types of thread safety mechanisms?
2: You have inconsistent lock protection of data access. In GetPage you access _cacheStorage before applying the lock, while in Deserialize, you access it inside a lock. This means that you may get a result where one is adding to the cache while another is getting from it.
3: Do you require thread safety for the cache, for xml reading, or both?
If you only need to protect the cache, move reading of xml outside the lock. If protecting both, you should put the entire GetPage function inside the lock.

Singletons and ASP.NET MVC

Right now I'm having an issue with a Singleton that I just wrote for use in ASP.NET MVC -- My Singleton looks like this:
public sealed class RequestGenerator : IRequestGenerator
{
// Singleton pattern
private RequestGenerator()
{
requestList = new Stack<Request>();
appSettings = new WebAppSettings();
}
private static volatile RequestGenerator instance = new RequestGenerator();
private static Stack<Request> requestList = new Stack<Request>();
// abstraction layer for accessing web.config
private static IAppSettings appSettings = new WebAppSettings();
// used for "lock"-ing to prevent race conditions
private static object syncRoot = new object();
// public accessor for singleton
public static IRequestGenerator Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{
instance = new RequestGenerator();
}
}
}
return instance;
}
}
private const string REQUESTID = "RequestID";
// Find functions
private Request FindRequest(string component, string requestId)
private List<Request> FindAllRequests(string component, string requestId)
#region Public Methods required by Interface
// Gets and increments last Request ID from Web.Config, creates new Request, and returns RequestID
public string GetID(string component, string userId)
// Changes state of Request to "submitted"
public void SetID(string component, string requestId)
// Changes state of Request to "success" or "failure" and records result for later output
public void CloseID(string component, string requestId, bool success, string result)
// Verifies that Component has generated a Request of this ID
public bool VerifyID(string component, string requestId)
// Verifies that Component has generated a Request of this ID and is owned by specified UserId
public bool VerifyID(string component, string userId, string requestId)
// Returns State of Request ID (Open, Submitted, etc.)
public Status GetState(string component, string requestId)
// Returns Result String of Success or Failure.
public string GetResult(string component, string requestId)
#endregion
}
And my controller code looks like this:
public ViewResult SomeAction()
{
private IRequestGenerator reqGen = RequestGenerator.Instance;
string requestId = reqGen.GetID(someComponentName, someUserId);
return View(requestId);
}
Everything works okay the first time I hit the controller. "reqGen" is assigned the instance of the Singleton. A new instance of Request is added to the internal list of the Singleton. And then we return a View(). The next time I hit this controller's SomeAction(), I'm expecting the Singleton to contain the List with the instance of SomeClass that I had just added, but instead the List is empty.
What's happened? Has Garbage Collection gobbled up my object? Is there something special I need to consider when implementing the Singleton pattern in ASP.NET MVC?
Thanks!
EDIT: Ahh, the lightbulb just went on. So each new page request takes place in a completely new process! Got it. (my background is in desktop application development, so this is a different paradigm for me...)
EDIT2: Sure, here's some more clarification. My application needed a request number system where something being requested needed a unique ID, but I had no DB available. But it had to be available to every user to log the state of each request. I also realized that it could double as a way to regulate the session, say, if a use double-clicked the request button. A singleton seemed like the way to go, but realizing that each request is in its own process basically eliminates the singleton. And I guess that also eliminates the static class, right?
EDIT3: ok, I've added the actual code that I'm working with (minus the implementation of each Method, for simplicity sake...) I hope this is clearer.
EDIT4: I'm awarding the green check mark to Chris as I'm beginning to realize that an application-level singleton is just like having a Global (and global's are evil, right?) -- All kidding aside, the best option really is to have a DB and SQLite seems like the best fit for now, although I can definitely see myself moving to an Oracle instance in the future. Unfortunately, the best option then would be to use an ORM, but that's another learning curve to climb. bugger.
EDIT5: Last edit, I swear. :-)
So I tried using HttpRuntime.Cache, but was surprised to find that my cache was getting flushed/invalidated constantly and couldn't figure out what was going on. Well, I was getting tripped up by a side-effect of something else I was doing: Writing to "Web.config"
The Answer --> Unbeknownst to me, when "web.config" is altered in anyway, the application is RESTARTED! Yup, everything gets thrown away. My singleton, my cache, everything. Gah. No wonder nothing was working right. Looks like writing back to web.config is generally bad practice which I shall now eschew.
Thanks again to everyone who helped me out with this quandary.
The singleton is specific to the processing instance. A new instance is being generated for each page request. Page requests are generally considered stateless so data from one doesn't just stick around for another.
In order to get this to work at the application level, the instance variable will have to be declared there. See this question for a hint on how to create an application level variable. Note that this would make it available across all requests.. which isn't always what you want.
Of course, if you are trying to implement some type of session state then you might just use session or use some type of caching procedure.
UPDATE
Based on your edits: A static class should not maintain data. It's purpose is to simply group some common methods together, but it shouldn't store data between method calls. A singleton is an altogether different thing in that it is a class that you only want one object to be created for the request.
Neither of those seem to be what you want.
Now, having an application level singleton would be available to the entire application, but that crosses requests and would have to be coded accordingly.
It almost sounds like you are trying to build an in memory data store. You could go down the path of utilizing one of the various caching mechanisms like .NET Page.Cache, MemCache, or Enterprise Library's Caching Application Block.
However, all of those have the problem of getting cleared in the event the worker process hosting the application gets recycled.. Which can happen at the worst times.. And will happen based on random things like memory usage, some timer expired, a certain number of page recompiles, etc.
Instead, I'd highly recommend using some type of persisted storage. Whether that be just xml files that you read/write from or embedding something like SQL Lite into the application. SQL Lite is a very lightweight database that doesn't require installation on the server; you just need the assemblies.
You can use Dependency Injection to control the life of the class. Here's the line you could add in your web.config if you were using Castle Windsor.
<component id="MySingleton" service="IMySingleton, MyInterfaceAssembly"
type="MySingleton, MyImplementationAssembly" lifestyle="Singleton" />
Of course, the topic of wiring up your application to use DI is beyond my answer, but either you're using it and this answer helps you or you can take a peak at the concept and fall in love with it. :)

ASP.NET MVC Session vs Global vs Cache

I have an application that was written in vanilla ASP.NET that I would like to port over to ASP.NET MVC.
I, however, am confused about the right place to persist objects. I need to persist for a couple reasons:
I would like all to have a single database connection, wrapped in a "repository" or "manager" style object.
Each user has a user object that needs to be saved on a per-session basis.
Normally, I would say that #1 would be saved as a static item in the Globals.asax that can be hit using Global.Repository or similar.
And I would normally say that #2 should be a property with a session backing store somewhere in the base class of the pages.
Now the reason I am confused is that I have heard that sessions have changed in MVC, and the Global.asax no longer holds the same class. Also, the concept of pages has been removed, so adding a property to the base class of a controller seems... wrong.
What say yall?
Your database would go in a base class for your controllers. This base class should extend Controller, and all your controllers should extend the base class. Here's a little example:
public class BaseController : Controller
{
private AuthServices _auth;
private LogHelper _log;
private Repository _repository;
/// <summary>
/// <see cref="AuthServices"/>
/// </summary>
protected AuthServices Authorization
{
get { return _auth ?? (_auth = new AuthServices()); }
}
/// <summary>
/// <see cref="LogHelper"/>
/// </summary>
protected LogHelper Log
{
get { return _log ?? (_log = new LogHelper()); }
}
/// <summary>
/// <see cref="Repository"/>
/// </summary>
protected Repository Repository
{
get { return _repository ?? (_repository = new Repository()); }
}
}
Notice the lazy instantiation. That allows me to sneak in before running tests and set my private fields with mocks.
As for the session, your User object can still be saved in the session just as in a traditional ASP.NET application. Almost everything is still around (Response, Cache, Session, etc), but some of them have been wrapped with classes from System.Web.Abstractions so that they can be mocked for testing. They all still behave the same way, though you shouldn't use some of them in their traditional role (e.g., don't Response.Redirect, return an ActionResult such as RedirectToRouteResult that performs your redirection).
As for the reasoning behind your questions....
Don't stress on a single db connection. Depending on your implementation it may even be a bad idea, as requests may step on each other. Just open your connex, use it, and dispose/close it when done.
Also, one of the biggest changes that MVC brings is the rejection of the stateful model that traditional ASP.NET attempted to bring to web development. All that framework and viewstate doesn't exist anymore (pay no attention to the man behind the curtain). The less state you hold onto the less complex and more robust your web application is. Try it, you might like it.
If you use sessions I would recommend having a session class, so that you only need to specify the string name once in code and this will give you IntelliSence also.
public static class SessionHandler
{
// User Values
private static string _userID = "UserID";
private static string _userRole = "UserRole";
public static string UserID
{
get
{
if (HttpContext.Current.Session[SessionHandler._userID] == null)
{ return string.Empty; }
else
{ return HttpContext.Current.Session[SessionHandler._userID].ToString(); }
}
set
{ HttpContext.Current.Session[SessionHandler._userID] = value; }
}
public static string UserRole
{
get
{
if (HttpContext.Current.Session[SessionHandler._userRole] == null)
{ return string.Empty; }
else
{ return HttpContext.Current.Session[SessionHandler._userRole].ToString(); }
}
set
{ HttpContext.Current.Session[SessionHandler._userRole] = value; }
}
}
Sessions haven't changed at all in MVC. The GlobalApplication class in Global.asax still exists, too. Pages exist, also, that you would want to refer to a repository in a controller rather than a page. Adding a property to a base controller class is fine; I do it all the time.
You can create a model binder to encapsulate state.
(See Steve Sanderson's mvc book on his shopping cart implementation)
With the model binder, you have access to the controllerContext - which has the HttpContext.

Resources