I'm experimenting with implementing a lightweight mvp framework with Delphi 2009.
Views are passive but supports databinding (via an interface property).
I'm facing a dilemna:
I've several very similar views/presenter/model triad, ie :
order form and a customer form = behavior and logic is the same but the datasource for databinding is different and the form title too. the datasource is a common property for all my models so it's not a problem, to set the form title, I'm forced to hard code it in my presenter InitView method
All is working good, but I'm in a situation where I have several simple mvp triads very similar. I want to refactor it but in that case I will have to pass some parameters to the mvp constructor.
So far I'm doing like that :
Create the view
Create the model
Create the presenter and inject model and view in the constructor
In fact, I'm facing a choice :
Having some very generic views/presenter, use them like that but inject 1 or 2 parameters in the constructor
Having some views/presenters superclass, and derive all my similar view/presenter from them and set some specific values in the overriden methods.
Can you give me some hints / advices ?
(sorry if i'm not very clear)
Fred,
I will choose 1 & 2 in a way that is having an abstract views/presenters that contain generic behaviors and creates abstract functions that could be possible specific behaviors implemented by subclasses.
for example,
public abstract class AbstractPresenter{
// subclass will be implemented
public abstract void InitView(Model model, View view);
}
and then you might have sublcasses, OrderFormPresenter and CustomerFormPresneter extends from AbstractPresenter.
public OrderFormPresenter extends AbstractPresenter{
public void InitView(Model model, View, view){
// do something specific values
}
}
public CustomerFormPresenter extends AbstractPresenter{
public void InitView(Model model, View, view){
// do something specific values
}
}
Please, correct me if it goes wrong direction.
I hope it helps.
Tiger
I'd create a generic view/presenter with parameters and subclass only when needed.
Another approach (and the way that I once solved this problem so it worked very well) is to build a generic "metadata" interface into the model, and the view (either interfaces, or via class inheritance) then use these generic interfaces in your presenter. I chose to use inheritance for my model, and interfaces for my view (was easer to slap a interface on an existing form than to require form/frame inheritance across the board). In my solution, the constructor for the presenter took 3 parameters, the model, the view and the "MVP name". I used the name of the MVP to load settings which were specific to the current scenario.
Related
I'm working on ASP.NET MVC application & have a quick design question for you.
So I need to implement a common functionality for all my controllers (well, most of them).
I don't want to repeat the same logic in all the controllers.
What'd be the ideal approach in the best interest of MVC?
I found people saying create base controller and inherit it in your controllers. But when I visualize a controller, I can see it'd contain only action methods that return some content/views - Correct me if I'm wrong.
OneController
{
ActionMethod A1
{
//Code to return list of objects for the given integer value. So it calls database stored procedure.
}
}
...multiple such controllers are there.
I'd still like to have A1 exists in the OneController, just put its logic somewhere common place.
Also some people suggest to create just plain Helper class to place the common method.
Could you please suggest me what approach will be better (Or any other appropriate approach)? Thanks.
I agree with you that, most of the times, it only makes sense to inherit from base controllers when we're talking about Actions or methods that are really related. But of course, you can just use base controllers for everything. Your choice.
Other than that, you have 2 options. For classes that have little to no chance of being polymorphic (change behavior depending on the implementation), you are fine to create static classes and just use them inside your controllers. An example would be a class that does math calculations, these are not that polymorphic by nature.
For all the other cases, I'd strongly suggest that you use dependency injection. One of the reasons being that unit testing will become way easier. Here's a guide on how to do it for MVC 4 onwards using the built in engine: https://www.asp.net/mvc/overview/older-versions/hands-on-labs/aspnet-mvc-4-dependency-injection. If you don't want to use it and use Ninject or Simple Injector, you can implement your own ControllerActivator and use Ninject, for instance, to get an instance of your controller.
When using dependency injector, normally your controller would get the dependencies in the constructor, like this:
public class StoreController : Controller
{
private IStoreService service;
public StoreController(IStoreService service)
{
// service in an injected dependency
this.service = service;
}
}
For more information, Google ASP.NET dependency injection.
I am developing an MVC app to serve multiple domains - each is a branch of a larger company.
A LocalBranch class stores details such as phone, address, email, location coordinates etc.
I want to create a single instance of this class per http request and have it available throughout the application - from within controllers, views, some helper classes and other code.
Is there a recommended way of doing this?
Right now I have it as a property on a BaseController and use ViewBagto pass it to views. But I would prefer it strongly typed in Views if possible.
I don't want to put it in an application variable, because we need to serve different values to different domains.
I would rather avoid a session variable if possible because we might scale up to use multiple servers in the future, and I've heard this doesn't play well with sessions.
Please feel free to update tags / title if you think there is a clearer way of expressing what I'm after. Thank you.
The best way to maintain your state in a web application per request is simply use the HttpContext class.
You need to store your state(LocalBranch) as an Item in the HttpContext:
HttpContext.Current.Items.Add("LocalBranch", GetLocalBranch());
You can fetch the Item all across your application like this:
LocalBranch branch = HttpContext.Current.Items["LocalBranch"] as LocalBranch;
The Items property is simply a key value Dictionary. The value is an object. You will have to check for nulls and this is really similar to the Session object you know. The main difference is the scope. The HttpContext is a dot net object that has a lifetime of an http request.
Now using the HttpContext the way I've shown you is the simplest way to do it.
You can go two steps forward and use a framework called Unity and add a lifetime to your objects.
Unity does much more and the lifetime management is just one gem.
You can create a custom HttpContext lifetime that generates objects per request. Something like this.
And them all you need to do is:
1.Register you LocalBranch class with the HttpContext lifetime.
2.Add a static Current property which will use the Unity container and resolve the correct instance of LocalBranch.
3.Use it something like this: LocalBranch.Current
BTW, you can use Unity's dependency injection for injecting objects into controllers and other modules. That's a better practice then just using the static Current property.
You kind of have two questions here. The first is "How do I create a single instance of this class per HttpRequest?" The second is "How do I make this available to strongly typed views?"
The first has pretty much been answered by #amir-popovich to use dependency injection. However, FWIW I would probably use Ninject instead of Unity (just preference, really) and I would probably implement it differently. I would not use HttpContext, and simply build a service (which is instanciated using Ninject's OnePerHttpRequest Module, passing the domain as an argument to get the proper values).
Then, in order to add these LocalBranch values to your strongly typed View Model, you can first create a base view model which holds this type:
public class BaseViewModel
{
public LocalBranch Branch {get;set;}
}
Then, make all of your current view models inherit this base type
public MyViewModel : BaseViewModel
{
public string SomeValue {get;set;}
}
Then in your controller, it is easy enough to add these values from the service you created from the first step
public ActionResult SomeAction()
{
var vm = new MyViewModel();
vm.Branch = LocalBranchService.GetLocalBranchValues(); //Local Branch Service has been injected with Ninject
//do other stuff
return View(vm);
}
However, that gets pretty tedious to add that to each controller action, so you can instead create a Result Filter to add it for you:
public class LocalBranchResultFilter : FilterAttribute, IResultFilter
{
public void OnResultExecuting(ResultExecutingContext filterContext)
{
//This method gets invoked before the ActionResult is executed.
filterContext.Controller.ViewData.Model.Branch = LocalBranchService.GetLocalBranchValues(); //Local Branch Service has been injected with Ninject
}
}
Now, you can just decorate your Controller and/or Actions with the filter (you could even set it in the Global Filters if you want).
You can embed the child actions into your layout or a view. You can even cache its output so you don't keep re-querying the database.
controller
[ChildActionOnly]
[OutputCache(Duration=500, VaryByParam="*")]
public ActionResult Info()
{
var localBranch = db.GetLocalBranch();
return PartialView("_Info", localBranch);
}
_Info view
This bit will get inserted into your other views
#model LocalBranch
<span>#Model.address</span>
<span>#Model.phone</span>
Use in _Layout or other view
<p>lorem ipsum...</p>
#Html.Action("Info")
In MVC 3, I understand you can create custom WebViewPages. Can you inject dependencies, using constructor injection, via an IOC container?
There is an expample for view injection in a blog post by Brad Wilson http://bradwilson.typepad.com/blog/2010/07/service-location-pt3-views.html
The statements of the others that views allow constructor injection not entirely correct. Yes IDependencyResolver enables creating views that have constructor arguments. But unless you are implementing your own view engine this won't help you at all. Existing view engines like razor will require that you have a parameterless constructor. This means you can do only property injection on views with them.
But as the others said you shouldn't do view injection anyway. Your view should be dumb and just render the view model to HTML. Anything requiring a dependency should be done in the controller or a service.
It is not possible to perform constructor injection. But you can do something like this with, say, Ninject:
public abstract class CustomViewBase<TModel> : WebViewPage<TModel> where TModel : class
{
[Inject]
public IFace Face
{
get;
set;
}
}
And assuming you have set up IDependencyResolver in Global.asax you should correctly have the #Face property initialised. But one important caveat: you may not access #Face in _Layout.cshtml, because (according to Brad Wilson) Layout works outside MVC, and #Face will be null when you try to access it in the layout page.
In any case I agree with the others in that the view should not have to deal with any complex logic.
Yes, it is possible, but i really think it is not a good idea. Why would you need some "services" on the view level ? Remember the key MVC guideline - a view must be dumb. In fact, it should be just some sort of template for transformation of view model object to HTML, nothing more.
I am working on my model hierarchy and have a few questions.
1) I have a base model for each view type (Add, Edit and View). I put thing in these that are specific to each view type.
2) I then have a model base which the bases above inherit from. This allows me to include things that pertain to ALL views.
3) In my ModelBase, i have a couple of other view models like FeedbackViewModel, ShoppingCartViewModel, etc that I can consume on any view.
4) I have my MasterPage inheriting ModelBase.
Example
Public MustInherit Class ModelBase
Public Property ErrorMessage As String
Public Property InformationMessage As String
Public Property WarningMessage As String
Public Property FeedbackModel As New FeedbackViewModel
End Class
Public MustInherit Class ViewModelBase
Inherits ModelBase
'View Model Specific Stuff
End Class
'Allows contact us form to be submitted.
Public Class ContactUsViewModel
Inherits ViewModelBase
Public Property Name As String
Public Property EmailAddress As String
Public Property Phone As String
Public Property Comments As String
End Class
That is the basic structure of my models, but a few questions:
1) What do I do with a view that requires no model, but I need to pass the FeedabckViewModel, SHoppingCartViewModel, etc.? I was thinking of a GenricViewModel?
2) Do you see any flaws in this design?
Thank You!
Some points:
Why use ErrorMessage, InformationalMessage, WarningMessage, etc. ModelState should be more than enough, and it ties in better with the validation helpers as opposed to you writing the manual stiching in the View.
I think a "base" model to handle different view types is a bit overkill. I think a enum specifying the mode would be better, then you can make decisions accordingly.
Overall, there is nothing really wrong with your design. It's a matter of opinion - for which mine is i usually create a ViewModel per View. Keeps it simple. I use areas extensively so it doesn't get messy. I generally try and create the ViewModels to make the View simple - that's the ultimate goal, not to re-use code across View's, but to keep the View simple. Such as augmenting the model with nested models to make use of partials/templates, as opposed to having a bunch of strings.
1) What do I do with a view that requires no model, but I need to pass the FeedabckViewModel, SHoppingCartViewModel, etc.?
Doesn't that kind of contradict itself? :) If you just need "parts" of a couple of ViewModels, either create another ViewModel, or if it's just a couple of fields, just stick it in the ViewData.
How do bind my domain object Car to View?
MVC says "your class must have default constructor". But I don't want to change any business rules by creating a default constructor. The only solution I can see - is to use CarView in my View and then map it to Car.
P.S. NHibernate wants a default constructor too, but it can be protected. This I can do.
IMHO, its a good idea to seperate the objects that go to your view from you domain objects. This has a long list of advantages (which I am not going into now).
You can then use Automapper to map your view models to your domain objects
You could create the object yourself and call UpdateModel to do the binding instead:
public ActionResult MyAction()
{
var car = new MyCar(somethingToPassIntoTheConstructor);
UpdateModel(car);
// Do stuff with car.
}