enforcing ObjectStateManager entry deletion on page leave - asp.net-mvc

I have a edited RESTful wizard based upon Shoulders of Giants | A RESTful Wizard Using ASP.Net MVC… Perhaps? . This wizard has a CANCEL button which, when pressed, fires the code below.
// If the user cancels, drop out altogether
if (!string.IsNullOrEmpty(CANCEL_BUTTON)) {
Session.Remove(VACANCYWIZARD_SESSION_KEY);
repository._entities.ObjectStateManager.GetObjectStateEntry(inProgressVacancyWizard.Vacancy).Delete();
return this.RedirectToAction("Index", "Home");
}
Now, to be able to call SaveChanges() after the cancel button I have to manually delete the entry from the wizard from my ObjectStateManager. But when you cancel the wizard by just manually returning to the home page it stays in and a next call to _entities.SaveChanges() will throw an exception that it cannot Save the object, from the wizard progress to the database, since it is still in the object state.
Note that in between the steps of the wizard I do not save anything to the database. I keep it in session state retrieving it each step:
NewVacancy inProgressVacancyWizard = Session[VACANCYWIZARD_SESSION_KEY] as NewVacancy;
Somehow, however, the inProgressVacancyWizard.Vacancy does appear in the ObjectStateManager so I have to delete it else I will get errors about incomplete Vacancies models while the _entities.SaveChanges() is called for another object.
Is there a way to cover for this problem?
//edit
After some reading I have found out that the fundaments of my repository are not good. As found here. Currently I'm doubting to implement the option mentioned in "One ObjectContext instance per business transaction" in the same article. Would that be a wise thing? I would like to hear some more about it since it will be a major refactor.
public static Repository Instance
{
get
{
if (instance == null) {
instance = new Repository();
}
return instance;
}
}
#region Constructor: Repository()
/// <summary>
/// Constructor
/// </summary>
private Repository()
{
_entities = new DBModelEntitiesNew2();
}

It seems like you are using a single ObjectContext instance across multiple requests. Don't do that. It will cause you nothing but misery. It makes your web server stateful. Dispose the ObjectContext after the response is rendered (we do it, indirectly, from Controller.Dispose), and new up a new one for the next request.

Related

Jhipster, prevent user to update entities created by other users

I have been implementing Jhipster at my work and loving it. I was asked to implement a security validation that one user should not be allowed to edit the entity created by other user. For this I need two things:
First, in all entities, add a ManytoOne relation with User entity.
In Backend put a validation in controller while updating the entity to check if current logged in user is same as what is stored in DB. In front end also same logic to show/hide edit button.
I have done a POC for this and it works but is little ugly, check the code:
public ResponseEntity<Entry> updateEntry(#RequestBody Entry entry) throws URISyntaxException {
log.debug("REST request to update Entry : {}", entry);
if (entry.getId() == null) {
throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull");
}
//here is my logic
Optional<Entry> entry_db = entryRepository.findOneWithEagerRelationships(entry.getId());
if(!entry_db.get().getUser().getId().equals(userService.getUserWithAuthorities().get().getId())) {
//throw someexception
}
//
Entry result = entryRepository.save(entry);
return ResponseEntity.ok()
.headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, entry.getId().toString()))
.body(result);
}
Is there any better or OOTB way of doing this??? may be something in spring security i am not aware of??
Thanks for help!!
This is a job for Spring Security Expression-Based Access Control, in particular you could annotate your method with #PreFilter and a custom PermissionEvaluator you would implement with similar logic as in your POC. The PermissionEvaluator could be generic and applied to several entity types if you define an Owned interface that models the ownership with a method like User getOwner() and that all your entity classes would implement.
See https://docs.spring.io/spring-security/site/docs/current/reference/html5/#el-access
The annotated method should be in a service rather than in a resource controller.
Also, UserService alone will not help you in finding the current authenticated user, you should use JHipster's SecurityUtils first and then ÙserService if you need more data about it.

Calling SaveChanges once per request in Asp.Net MVC application

I'm trying to create a mostly simple web app with Asp.Net MVC and Entity Framework. I actually finished few projects with it but wasn't satisfied about the code so I'm following some more popular ways to do it. Here is my structure:
Controller gets the request,
I have services which contain business logic. They also use my Database Context to change the data on the database. I didn't want to create another database layer so I'm using them,
I inject my services to controller (with Unity) and call stuff like CustomerService.Delete(Id)
My service deletes the data based on Id.
So my controller does not include any logic or database operations, my services does include both. I think it's a good way to do stuff but I have a problem.
Let's say I add a customer for the first time and there is another table keeping their balance and I want to include a bonus $10 for first registration, when I call my CustomerService.Add(Customer), that method also calls CustomerService.AddBalance(Customer, 10). In those methods I call DbContext.SaveChanges, here is the problem, I call SaveChanges 2 times, and if CustomerService.AddBalance(Customer, 10) fails for some reason I will still have the customer data but not the balance one. I know I can use a transactions but where do I put that code? If I knew there was a place which runs last before request is finished, I could call SaveChanges() there and it would work but I think that's not a great idea either.
Basically I want to call SaveChanges() once per request but I couldn't find a good place to do it.
Thanks
If you are doing any work with the database you want to be using transactions. If you don't you are going to leave your db in an inconsistent state if one of your calls fails. Using transactions, nothing will be committed in the database until you call Commit. You can call SaveChanges as much a you like and it won't make a difference.
You can create a TransactionScope in a attribute and then add it to any controller action where you are accessing the db. Here' one I use
[AttributeUsage(AttributeTargets.Method)]
public class TransactionAttribute : ActionFilterAttribute
{
private TransactionScope TransactionScope { get; set; }
public override void OnActionExecuting(HttpActionContext filterContext)
{
TransactionScope =
new TransactionScope(TransactionScopeOption.Required, new TransactionOptions
{
IsolationLevel = IsolationLevel.ReadCommitted
});
}
public override void OnActionExecuted(HttpActionExecutedContext filterContext)
{
if (TransactionScope == null)
return;
if (filterContext.Exception == null)
{
TransactionScope.Complete();
return;
}
TransactionScope.Dispose();
}
}
You could put the transaction code in BeginRequest stash it in HttpContext and commit on EndRequest. This is going to create a TransactionScope for every call that asp.net handles.
According to documentation EF by default sets all the changes to database in transaction until SaveChanges() is called.
So you can extract the logic of adding to database to separate methods, create separate method which saves changes to DB and design your code as following:
AddCustomer to DB (do not call save changes)
AddBalance to DB(do not call save changes)
SaveChanges on the end of the in your service method
This will guarantee that all happens in transaction and in case of any error changes to database won't be applied.
I have found that creating an Extension to your Context (i am assuming your are using EF) is a good way to go:
public static class TIContextCompleteExtention
{
public static void Complete(this TIContext context)
{
try
{
context.SaveChanges();
}
catch (Exception ex)
{
throw ex;
}
}
public static async Task CompleteAsync(this TIContext context)
{
try
{
await context.SaveChangesAsync();
}
catch (Exception ex)
{
throw ex;
}
}
}
The Above TIConext is derived from EF's dbContext.
Wherever you need to COMPLETE your transaction use
_context.Complete(); or _context.CompleteAsync() instead of EF's SaveChanges() / SaveChangesAsync()
If you later swap out your ORM all you need to do is change the above extensions to fit your new Context.
Hope this helps.

Why global property in MVC Controller is still empty

I have this code in my Controller:
List<string> order = new List<string>();
[Route("Reservations/Overview/Refresh/id")]
[AllowAnonymous]
public JsonResult AddOrder(string id)
{
if(!order.Contains(id))order.Add(id);
return Json($"ok", JsonRequestBehavior.AllowGet);
}
[Route("Reservations/Overview/Check/id")]
[HttpPost]
public JsonResult Check(string id)
{
if (order.Contains(id))
{
order.Remove(id);
return Json(true);
}
else return Json(false);
}
Everything is working but my global order list is always empty. Why?
HTTP is stateless. Each request instantiates a new instance of the controller class, which wouldn't reflect any changes made to class-level variables on a previous instance (which has long since been disposed) from a previous request.
Basically you need to persist your data somewhere. There are a variety of places to do this:
Session state
Static values
A database
A cache mechanism
On the page itself (posted back with form data)
Cookies
A file
and so on...
Each option is going to have its pros and cons, depending on the full set of functionality you need. Session state may be the simplest approach to get you started. On the page itself may be considered more RESTful and, thus, more scalable/portable. A database would be more secure than on the page itself because users can modify anything on the page. Etc.
But the point remains regardless of which option you want... The data needs to be persisted (saved) somewhere in order to be able to read it again at a later time.
Global variables are not persisted across multiple requests to the controller. You can persist them to a database, or store the orders in session:
Session["Orders"] = orders;
You have to store the updated list of orders to session every time you modify the list or data within the list in any way. Session is per user; just be careful how much data you put in session if you do. If you use a database, you need to persist the record change anytime a value changes on a record, or when creating a new record.

Add to DB using SaveChanges() in Entity Framework with object from another scope

I'm new using entity framework, and I'm trying to insert into the DB.But I'm having an issue, because I need to only SaveChanges from objects of other 3 scopes. Like this:These are my three Actions that Add the objects into my entities:
public void AddEndereco(entidade_endereco entEndereco)
{
db.entidade_endereco.Add(entEndereco);
}
public void addContato(entidade_contato entContato)
{
db.entidade_contato.Add(entContato);
}
public void addBanco(entidade_banco entBanco)
{
db.entidade_banco.Add(entBanco);
}
And in this action I need to insert all the objects into my DB:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(entidade entidade, string Grupo, string Situacao)
{
if (ModelState.IsValid)
{
if (Grupo != "")
entidade.gre_codigo = Convert.ToInt32(Grupo);
if (Situacao != "")
entidade.sie_codigo = Convert.ToInt32(Situacao);
if (entidade.ver_ativo)
entidade.ent_ativo = "S";
else
entidade.ent_ativo = "N";
if (entidade.ver_cliente)
entidade.ent_cliente = "S";
else
entidade.ent_cliente = "N";
if (entidade.ver_fornecedor)
entidade.ent_fornecedor = "S";
else
entidade.ent_fornecedor = "N";
//ADDING ANOTHER OBJECT
db.entidades.Add(entidade);
//HERE IS WHERE I NEED TO SAVE ALL (entidade_endereco, entidade_contato, entidade_banco, entidade)
db.SaveChanges();
return RedirectToAction("Index");
}
return View(entidade);
}
But it is only saving the entidade object, the others don't exist anymore when db.SaveChanges() is executed.
How can I insert into the DB with objects that were added to my entity in other scopes?
If you really want to make this work as is, you would need to store either the Context (really bad idea) or Entities (slightly less bad) across requests. Session State jumps to mind, but using it can bring in a whole load of new pain.
Ideally, you should change your design to take advantage of the stateless nature of HTTP. Each action method should be a separate transaction, saving the data from it's execution when the method is done. If those separate entities only make sense when they are all saved together, then you need to create all of them within a single action and save them to the context together. Managing the boundaries of different business entities and when they are saved is a critical part of application design, I highly recommend you read about Aggregate Roots within Domain Driven Development. Even if you don't go the full DDD route, the Aggregate Root concept will be extremely helpful to you. The CQRS Journey from Microsoft gives an in-depth tutorial of these concepts (and many others)
Im not sure, if I got your question right (excuse my poor spanish). In the Action Create you only add "entidade" to your entidades collection, and so its the only one affected by SaveChanges(). If you want to add others, include in the Create-Action or try making a EF-transaction.
Without transaction the context is lost after the Create-Method ends

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. :)

Resources