I've created a object that I'd like to have accessible from wherever the request-object is accessible, and to "die" with the request, more or less like how you always in a mvc-application has access to the RouteData-collection. Especially it's important that I have access to this object in the execution of action-filters. And also there need to be created a new object of my class whenever a new request is made to the page (the object needs to be request-safe, ie. only one request modifies that one object).
Any thoughts about how to achieve this?
HttpContext is a good place for this. The Items dictionary could be used to store objects relative to the request.
Related
I have an instance controller containing data which i need to filter in a separate function within the same controller. From what I've read this seems to be impossible, since the lifespan of an instance variable is only in the request. So in what way can i get a hold of the data in the instance controller which was served in the previous request? I know that you can use hidden fields and store it in session but there has to be a better way?
Use flash?
http://guides.rubyonrails.org/action_controller_overview.html#the-flash
flash[:my_object] = json_object
I don't think it is good for complete objects but maybe store the entire object in your DB and falsh the id. Or just flash some key parameters.
I'm playing around with ASP.NET MVC 4, but I have some problems with understanding. For better explanation I will use a simple "synthetic" situation.
Let's say I have model Person with 2 properties:
string Name
PersonType Type (e.g. Student, Employee, Military...)
Let's say in my controller I have private property Person. I can initialize this object in Index method, pass into View and build html page. Ok.
Now when user updates one of fields of person instance at the client side (he can input a new person name or select new person type using dropdown list), I want to update my model immediately. So, my general question is How can I achieve it?
Obvious solution for me: I can send an ajax request to controller from JS with new data. I thought that I can call controller's method UpdateName(string name) and update manually property Name with new data. BUT my person instance is NULL inside of this method! My second question is Why I can't access to initilized model object from other method? I think it's all about my bad understanding of client server interaction.
The final case of my situation: when user click's on the button "Save" I want to save created person into file on the server side, but I don't want to use any forms and receive all needed data just after clicking this button (because in my real task I can't use forms and also I can't receive all needed fields from html page after button clicking).
I have found the dirty solution. In JS I created another class Person with same properties. Now I can update instance of this class when I want and pass json data to server for saving it.
Is there any better solutions?
Its not that dirty to have javascript objects to represent your model. In fact thats how I do it. I use KnockoutJS to give me a client side model - which is essentially the MVVM pattern.
You are trying to use the MVC model in a way which you can't. However, the Knockout model you can use how you wish. You basically have a javascript representation of your server side model and once you are done with it you send it to the server.
In order for your server side methods to pick up your client side model you simply have to ensure the post request contains the data and as long as properties names are the same in the parameters of the method they will match themselves.
Why I can't access to initilized model object from other method?
Because it's not initialized anymore. Don't use the controller class to store persistent data across requests. The controller object is disposed after a request completes and then re-initialized on a new request. So anything that one action methods saves at the class level is gone when you get to another action method. Each request from the client to the server should be considered a fully isolated event, independent of any previous requests.
When you want to save your model, what you would do in that action is re-fetch it from the database, apply the changes, and save it back to the database.
but I don't want to use any forms
I'm not really sure what you mean here. Do you mean you want to use AJAX instead of POSTing the page directly? If so, that's fine. There are probably a number of tools out there to help you, personally I often just create a form anyway but instead of a submit button I have a plain button and add some JavaScript code (using jQuery) to serialize the form and perform an AJAX POST.
As long as the keys for the POST values map to your model fields in the same way they would in an out-of-the-box form, then your action method will still be able to receive the proper model type. On the server-side it doesn't matter if it's from an AJAX call or a normal POST. The difference, however, is that the response for an AJAX call should probably be in JSON format instead of responding with a view.
So instead of this:
return View(someModel);
You might have something like this:
return Json(someModel);
I've been working with ASP.NET(WebForm) for a while, but new to ASP.NET MVC. From many articles I've read, in most cases the reason that the controllers are hard to test is because they are accessing the runtime components: HttpContext (including Request, Response ...). Accessing HttpContext in a controller seems bad.
However, I must access these components somewhere, reading input from Request, sending results back via Response, and using Session to hold a few state variables.
So where is the best place to access these runtime components if we don't access them in a controller?
when you call a model method in your controller, the Request and Response objects are carrying the same value or outputting to the same source. the "page" is what matters there for these objects.
And one more thing, the Request,Session and Response objects may not be directly referenced in your models so you can use System.Web.HttpContext.Current to get the objects. They will function the same as its called from the controller.
And Controllers meant to be as a bridge between views and models, and models should work even if there isn't any Response or Request value in these objects, so I would use these objects' values as usual parameters to model methods instead of referencing them inside the model. It's the right usage of the MVC concept.
If you really must access access these objects from your controller you could always just abstract them and inject a mock instance of them to isolate your testing to just the controller.
In MVC the HttpContext is actually HttpContextBase. It is completely fine to use these classes directly. If you need to later test your controllers you can mock these classes very easily.
http://www.hanselman.com/blog/ASPNETMVCSessionAtMix08TDDAndMvcMockHelpers.aspx
I see nothing wrong with what you want to do.
Accessing HttpContext in a controller seems bad.
No it is not, it just requires you to think about how you will test your action. If you don't test, then you probably don't even have a problem. I recommend you test though.
In fairly new to MVC and I would like to use a session. I have a base controller and all my other controller inherit from my base. I need the session checked every time a page is hit.
What is the best way to go about this?
Updated
My session will need to store an id to be able to build the pages correctly. If the session doesn't have the ID I need to look up the information in DB. I don't want to use cache because IDs could be different for different users.
I recommend going the cache route.
Create a class called 'CacheHelper' and within it, a method called 'GetId()'
In the GetId() method, setup a Dictionary object to store your values and use the username as the key.
Each time you call GetId, check to see if the Key exists in your dictionary
myDictionary.ContainsKey(username);
If not, look it up in the database, add it to the dictionary, then resave it to cache.
This is a little out there but I have a customer object coming back to my controller. I want to just reconnect this object back to the database, is it even possible? I know there is a datacontext.customers.insertonsubmit(customer), but is there the equivalent datacontext.customers.updateonsubmit(customer)???
This is what I don't like about LINQ-to-SQL.
It generally works fine if you're querying and updating in the same scope, but if you get an object, cache it, and then try to update it later, you can't.
Here's what the documentation says:
Use the Attach methods with entities that have been created in one DataContext, and serialized to a client, and then deserialized back with the intention to perform an update or delete operation. Because the new DataContext has no way of tracking what the original values were for a disconnected entity, the client is responsible for supplying those values. In this version of Attach, the entity is assumed to be in its original value state. After calling this method, you can then update its fields, for example with additional data sent from the client.
Do not try to Attach an entity that has not been detached through serialization. Entities that have not been serialized still maintain associations with deferred loaders that can cause unexpected results if the entity becomes tracked by a second data context.
A little ambiguous IMHO, specifically about exactly what it means by "serialized" and "deserialized".
Also, interestingly enough, here's what it says about the DataContext object:
In general, a DataContext instance is
designed to last for one "unit of
work" however your application defines
that term. A DataContext is
lightweight and is not expensive to
create. A typical LINQ to SQL
application creates DataContext
instances at method scope or as a
member of short-lived classes that
represent a logical set of related
database operations.
So, DataContexts are intended to be tightly scoped - and yet to use Attach(), you have to use the same DataContext that queried the object. I'm assuming/hoping we're all completely misunderstanding what Attach() is really intended to be used for.
What I've had to do in situations like this is re-query the object I needed to update to get a fresh copy, and then do the update.
The customer that you post from the form will not have entity keys so may not attach well, also you may not have every field of the customer available on the form so all of it's fields may not be set.
I would recommend using the TryUpdateModel method, in your action you'll have to get the customer from the database again and update it with the form's post variables.
public ActionResult MySaveAction(int id, FormCollection form)
{
Customer updateCustomer = _Repository.GetCustomer(id);
TryUpdateModel(updateCustomer, "Customer", form);
_Repository.Save(updateCustomer);
}
You will have to add in all your own exception handling and validation of course, but that's the general idea.
You want to use the attach method on the customers table on the data context.
datacontext.customers.Attach(customer);
to reconnect it to the data context. Then you can use SubmitChanges() to update the values in the database.
EDIT: This only works with entities that have been detached from the original data context through serialization. If you don't mind the extra call to the database, you can use the idiomatic method in ASP.NET MVC of retrieving the object again and applying your changes via UpdateModel or TryUpdateModel as #Odd suggests.