How to share an object between functions of the same controller? - asp.net-mvc

I work with asp MVC 4. I have a single controller and I want to share the same object between his functions. I thought about a data member but it doesn't work. Here is my code :
public class MyController : Controller
{
public MyObject obj;
public ActionResult Index()
{
obj = new MyObject();
this.obj.GetData(); // Fill my object
return View();
}
public ActionResult MyFunction()
{
Console.Write(this.obj); // Always null
return View();
}
}
Is it possible to keep this object between functions ? I used to create TempData ou ViewBags for sharing data but I'm not sure if it's the right way to manage big objects.

It is null because MVC framework create a new controller to handle different requests, hence the obj is also different.
If you make your Object singleton or simply make it static, it will work.
public static MyObject obj;

Try this:
public class MyController : Controller
{
public MyObject obj = new MyObject();
public ActionResult Index()
{
this.obj.GetData(); // Fill my object
return View();
}
public ActionResult MyFunction()
{
Console.Write(this.obj); // Always null
return View();
}
}
This will stop your null error.
If you want to save data between postbacks, you will need to look into persistent data storage such as a SQL based database.

Related

Pass data between controllers asp.net mvc 3

I need to know how to pass data between two controllers in asp.net mvc 3
i have two controllers
public class controller1:Controller
{
}
public class controller2:Controller
{
}
how to pass data from controller1 to controller2?
One way is to pass using TempData:
public class controller1Controller:Controller
{
public ActionResult Index()
{
TempData["SomeKey"] = "Some Value";
return RedirectToAction("Index","controller2");
}
}
public class controller2Controller:Controller
{
public ActionResult Index()
{
string value = TempData["SomeKey"] as String;
return View();
}
}
One thing to remember is TempData is single read, which means that once a value is read from TempData it will automatically be deleted, if the value is till needed after read and you want to persist it, you have to call TempData.Keep() and you can be more specific to persist specific key value by calling:
string value = TempData["SomeKey"] as String;
TempData.Keep("SomeKey");
Another way is to use RouteValue Dictionary:
public class controller1Controller:Controller
{
public ActionResult Index()
{
return RedirectToAction("Index","controller2",new { SomeKey = "SomeValue"});
}
}
public class controller2Controller:Controller
{
public ActionResult Index(string SomeKey)
{
return View();
}
}
I am using String in example, you can have a custom type like a model or view model object that is to be passed.
I would suggest you to read this MSDN article for more details and understanding of passing data in mvc application.
You should also read What is ViewData, ViewBag and TempData? – MVC options for passing data between current and subsequent request and When to use ViewBag, ViewData, or TempData in ASP.NET MVC 3 applications
You can use RouteValue Dictionary here as :-
public class controller1Controller:Controller
{
public ActionResult Index()
{
return RedirectToAction("Index","controller2",new { UserName= "Username"}); <----Just pass username value here
}
}
public class controller2Controller:Controller
{
public ActionResult Index(string UserName) <-----get username value here
{
return View();
}
}

How do I save Entity with WCF

What is the best practice for saving an entity in wcf. I am calling my service through asp.net mvc site.
I have declared my context in the .svc file, as I would with normal winforms development.
public ScoolEntities database = new ScoolEntities();
Then I am using the following to get the data by id.
public student GetStudentsById(int id)
{
var q = (from mystudent in database.students where mystudent.id == id select mystudent);
return q.ToList()[0];
}
Then Finally I have a public save method
public bool savechanges()
{
database.SaveChanges();
return true;
}
Then in my controller I have
public ActionResult Edit(int id=0)
{
return View(obj.GetStudentsById(id));
}
[HttpPost]
public ActionResult Edit(MvcApplication1.ServiceReference1.student student)
{
if (ModelState.IsValid)
obj.savechanges();
return RedirectToAction("Index");
}
return View();
}
But it does not appear to save the changes and also what do I need to place in the return view I would have thought I call the GetStudents again but it does not appear to work?.
You need to add the Entity to the Context and need to call SaveChanges method.
database.Students.Add(student);
database.SaveChanges();

Will this code cause memory leak on my MVC application?

public class SomeViewModel
{
public List<Something> listOfSomethings = new List<Something>();
public Entity EntityObj;
etc...
etc..
..
}
public class Controller()
{
public SomeViewModel viewModel;
public ActionResult SomeAction()
{
viewModel = populateViewModel();
return View(viewModel);
}
}
The SomeViewModel is a large object that is populated in the controller's action. Will it be GC'd or cleared from memory when the controller is disposed?
There is no point of this public SomeViewModel viewModel; field in your controller. Controller actions are independant meaning that if you first invoke SomeAction which sets a value for this field and then invoke some other action do not expect this field to survive. So you should simply use this:
public class HomeController: Controller
{
public ActionResult SomeAction()
{
var viewModel = populateViewModel();
return View(viewModel);
}
public ActionResult SomeOtherAction()
{
var viewModel = populateViewModel();
return View(viewModel);
}
}
This being said your current code doesn't seem to have memory leaks because once the request ends the Controller class will be eligible for GC and so all its instance fields including the view model.
if populateViewModel method does not use disaposable resources (as data context) or uses and disposes them, your code should be fine.

I want to use session in the asp.net mvc controller constructor

I'm new to Mvc.
Sorry to my english. ^^
I have some question about asp.net MVC session in the controller.
The Scenario things that I want to do is like follows..
First of all, My development circumstance is entityframework and mvc3.
When Someone logged in each one has different database. So, Each has connect different database.
So, Each person has his own session value which is database connection string. So far so good.
I have simple database Repository and at the each repository's constructor can change database connection.
At controller which calls Repository class, I need session value. But As I know Controller's construction can't keep session value. right?
I want your good advice. Thanks in advance.
Code samples are below:
public class MasterRepository
{
DBEntities _db;
public MasterRepository(string con)
{
_db = new DBEntities(con);
}
}
public class TestController : Controller
{
private string con;
MasterRepository _db;
public TestController()
{
_db = new MasterRepository(Session["conn"].ToString()); // Session is null I want to solve this Part...
}
public ActionResult Index()
{
string con = Session["conn"].ToString(); // Session is assigned.
return View();
}
}
These should explain what's happening to cause Session to be null, and give you a few possible solution options:
Is ASP.NET MVC Session available at any point durign controller construction
Why my session variables are not available at construction of a Controller?
Session null in ASP.Net MVC Controller Constructors
I think you have missed out the "service" part of the controller - service - repository pattern:
http://weblogs.asp.net/fredriknormen/archive/2008/04/24/what-purpose-does-the-repository-pattern-have.aspx
But when you go down this path you will probably also need to learn IoC as well.
Then your code would look more like:
public class MasterRepository
{
public Foo GetAllFoo()
{
return ObjectContextManager.GetObjectContext().AsQueryable().ToList();
}
}
public class MasterService
{
MasterRepository _repository;
public MasterService(MasterRepository repository) // use IoC
{
_repository = repository;
}
public Foo GetAllFoo()
{
return _repository.GetAllFoo();
}
}
public class TestController : Controller
{
MasterService _service;
public TestController(MasterService service) // use IoC
{
_service = service;
}
public ActionResult Index()
{
var model _service.GetAllFoo();
return View(model);
}
}

Bestpractice DI with ASP.NET MVC and StructureMap - How to inject dependencies in an ActionResult

I edited my whole question, so do not wonder :)
Well, I want to have an ActionResult that takes domain model data and some additional parameters, i.e page index and page size for paging a list. It decide itself if it returns a PartialViewResult or a ViewResult depending on the kind of web request (ajax request or not).
The reffered data shall be mapped automatically by using an IMappingService, which is responsible for transforming any domain model data into a view model.
The MappingService uses AutoMapper for simplicity.
MappingActionResult:
public abstract class MappingActionResult : ActionResult
{
public static IMappingService MappingService;
}
BaseHybridViewResult:
public abstract class BaseHybridViewResult : MappingActionResult
{
public const string defaultViewName = "Grid";
public string ViewNameForAjaxRequest { get; set; }
public object ViewModel { get; set; }
public override void ExecuteResult(ControllerContext context)
{
if (context == null) throw new ArgumentNullException("context");
var usePartial = ShouldUsePartial(context);
ActionResult res = GetInnerViewResult(usePartial);
res.ExecuteResult(context);
}
private ActionResult GetInnerViewResult(bool usePartial)
{
ViewDataDictionary viewDataDictionary = new ViewDataDictionary(ViewModel);
if (String.IsNullOrEmpty(ViewNameForAjaxRequest))
{
ViewNameForAjaxRequest = defaultViewName;
}
if (usePartial)
{
return new PartialViewResult { ViewData = viewDataDictionary, ViewName = ViewNameForAjaxRequest };
}
return new ViewResult { ViewData = viewDataDictionary };
}
private static bool ShouldUsePartial(ControllerContext context)
{
return context.HttpContext.Request.IsAjaxRequest();
}
}
AutoMappedHybridViewResult:
public class AutoMappedHybridViewResult<TSourceElement, TDestinationElement> : BaseHybridViewResult
{
public AutoMappedHybridViewResult(PagedList<TSourceElement> pagedList)
{
ViewModel = MappingService.MapToViewModelPagedList<TSourceElement, TDestinationElement>(pagedList);
}
public AutoMappedHybridViewResult(PagedList<TSourceElement> pagedList, string viewNameForAjaxRequest)
{
ViewNameForAjaxRequest = viewNameForAjaxRequest;
ViewModel = MappingService.MapToViewModelPagedList<TSourceElement, TDestinationElement>(pagedList);
}
public AutoMappedHybridViewResult(TSourceElement model)
{
ViewModel = MappingService.Map<TSourceElement, TDestinationElement>(model);
}
public AutoMappedHybridViewResult(TSourceElement model, string viewNameForAjaxRequest)
{
ViewNameForAjaxRequest = viewNameForAjaxRequest;
ViewModel = MappingService.Map<TSourceElement, TDestinationElement>(model);
}
}
Usage in controller:
public ActionResult Index(int page = 1)
{
return new AutoMappedHybridViewResult<TeamEmployee, TeamEmployeeForm>(_teamEmployeeRepository.GetPagedEmployees(page, PageSize));
}
So as you can see the IMappingService is hidden. The controller should not know anything about the IMappingService interface, when AutoMappedHybridViewResult is used.
Is the MappingActionResult with the static IMappingServer appropriate or am I violating the DI principle?
I think a better design is to have a ViewResultFactory that depends on IMappingService, then you can inject that into your controller. Then you call it like so:
public class MyController : Controller
{
IViewResultFactory _viewResultFactory;
ITeamEmployeeRepository _teamEmployeeRepository;
public MyController(IViewResultFactory viewResultFactory)
{
_viewResultFactory = viewResultFactory;
}
public ActionResult MyAction(int page, int pageSize)
{
return
_viewResultFactory.GetResult<TeamEmployee, TeamEmployeeForm>(
_teamEmployeeRepository.GetPagedEmployees(page, pageSize));
}
}
The implementation would like this (you would need to create overloads for each of your HybridViewResult constructors):
public HybridViewResult<TSourceElement, TDestinationElement> GetResult<TSourceElement, TDestinationElement>(PagedList<TSourceElement> pagedList)
{
return new HybridViewResult<TSourceElement, TDestinationElement>(_mappingService, pagedList);
}
That way you hide the implementation from your controllers, and you don't have to depend on the container.
There are a few different points that you could inject IMappingService. http://codeclimber.net.nz/archive/2009/04/08/13-asp.net-mvc-extensibility-points-you-have-to-know.aspx is a good site for help in picking the appropriate extensibility points for .NET MVC.
If you want to stick with having this functionality be a derived ActionResult, then I think you could put the dependency in the ActionInvoker if you want to, but the Controller makes more sense to me. If you don't want the IMappingService in the Controller, you could always wrap it in a HybridViewResultFactory, and access that object in the Controller. In that case your shortcut methods would look like:
public HybridViewResult<TSourceElement, TDestinationElement> AutoMappedHybridView<TSourceElement,TDestinationElement>(PagedList<TSourceElement> pagedList, string viewNameForAjaxRequest)
{
HybridViewResultFactory.Create<TSourceElement, TDestinationElement>(pagedList, viewNameForAjaxRequest);
}
etc.
I'm not sure why you need to use an ActionResult, but if there is no reason that makes it explicitly necessary, you could create a HybridViewModel class and a HybridViewModelBinder class that is injected with the mapping service dependency.
I am assuming you want to use constructor injection, but if you have the StructureMap dependency in your UI assembly, you could access a static dependency resolver class (like Clowers said).
This question would be easier to give a definite answer to if I understood why you using an ActionResult.
It seems like you are using the action result to handle two functionalities that do not necessarily go together all the time, and that could be used separately. Also, there is not a clear indication that it needs to be in an ActionResult.
Presumably, you could (a) leverage the Automapper functionality for results other than html (ViewResult) output, and (b) you could leverage the functionality of auto-detecting ajax requests without needing to automap the model.
It seems to me like the automapping of the view model could be used to inject the view model into the controller action directly, thus removing the controller's dependency on the IMappingService. What you would need is a ModelBinder class to be injected with your IMappingService (the implementation of which I assume contains a repository or datastore type dependency).
Here is a good article explaining how to leverage model binders: http://odetocode.com/blogs/scott/archive/2009/04/27/6-tips-for-asp-net-mvc-model-binding.aspx.
Then you can overwrite the DefaultModelBinder in the classes that need to be Automapped as follows:
public ActionResult DoItLikeThis([AutoMap(typeof(MyDomainModelClass))]MyViewModelClass viewModel){
//controller action logic
}
Now, regarding the HybridViewResult, I would suggest that you handle this with an Action Filter instead. So, you could just use ActionResult or ViewResultBase as the Result type of your action method and decorate it with an action filter, i.e.:
[AutoSelectViewResult]
public ViewResultBase AndDoThisLikeSo(){
//controller action logic
}
I think overall this will be a much better solution than coupling these two functionalities to an ActionResult.

Resources