Reusable Content Box Data In ASP.NET MVC? - asp.net-mvc

If I create a PartialView for a box that holds a header, image and content what is the best way to store the content without using a database?
Example: TurboTax
I doubt the content for the boxes in the sidebar are stored in a database but to make reusable code it would be beneficial to create the structure in a PartialView and populate the content areas. I can create a PartialView and pass a Model from the parent Controller to the PartialView but then I would be stuck copying and pasting that same content if I wanted to use the same box on another page.

For fixed content you might want to think about using XML+XSLT or even HTML snippets in the file system and simply rendering them. An HtmlHelper method might make more sense for this than a partial view - Html.RenderXml() or Html.Include(). The only real difference between these and partial views is that the view engine isn't invoked since there aren't any substitutions. I do this sort of thing with my privacy policy and terms and conditions. I'd certainly consider keeping these cached.
If these really are templates and you are just substituting content, then I think the partial view works well and I would consider putting the data in a database, again, maybe using caching if I found that performance suffered. You could use this in combination with the former -- say keep your images/xml in the file system and a pointer to them in the database so you know which ones to pick in the partial.

Passing data to partial view that is used in many places can be done in many ways:
Create base model class for all your models. In base class define PartialModel property which will be holding model for partial view (there may be many of them if use have many partial views). Now you can populate the PartialModel property in controller action, but to make code more reusable you can create your own Action Filter which will insert the partial view data just after the action method is executed (but before the model is passed to the view)
public class PartialViewModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
BaseViewModel model;
if (filterContext.Controller.ViewData.Model == null)
{
model = new BaseViewModel();
filterContext.Controller.ViewData.Model = model;
}
else
{
model = filterContext.Controller.ViewData.Model as BaseViewModel;
}
model.PartialModel = new PartialModel(...) // Partial model initialization
base.OnActionExecuted(filterContext);
}
}
Then you can use it like:
[PartialViewModel]
public ActionResult Index()
{
//...
}
Another option: you can create BaseController class for all your controllers and create PartialModel on base controller initialization. Then PartialModel can be stored in ViewData[] dictionary. Because using ViewData dictionary in views is bad, create extension method on HtmlHelper like:
public static PartialModel GetPartialModel(this HtmlHelper helper)
{
return helper.viewContext.ViewData["PartialModel"] as PartialModel
}
So you could obtaint the model this way:
<% Html.RenderPartial("MyPartial", Html.GetPartialModel()); %>

Related

Entity - Automatically Create MVC Controller with dropdown

There's probably a really basic answer to this question but I am new to Entity and MVC and am getting used to the basics.
I'm trying to automatically generate a MVC controller for the main table Sites with a dropdown for server. It seems like I would need a model like this:
public class Sites
{
public TTSites TTSites { get; set; }
public List<servers> server { get; set; }
public Sites()
{
server = new List<servers>();
}
}
This is using the classes TTSites and servers both with string server
But if I set this as my model class and my entity database as data context it says I need to define a key. Should I be using the base classes instead of the model or what? Do i need to set something up in the model or base class?
It seems like you've got some terminology confused. You code the controller actions in a controller class, and the routing engine determines what controller action to call based on the URL. For example, if you have a HomeController class with a default Index action, it might look like this:
public ActionResult Index()
{
// code here
}
This would be invoked with the default routing, if you went to your site with a URL like this (let's say your site can be hit via the www.mysite.com URL:
http://www.mysite.com/Home
That would get you into the Index action in the controller.
Ordinarily, one would use a view model to use on the UI side, and that would be populated from an entiy with the data you need in the view itself. If you had two entities like TTSite and Server, you'd populate the Sites view model like so, as a (very simple) example:
public ActionResult Index()
{
var servers = yourDbContext.Servers.ToList();
var ttSite = yourDbContext.TTSites.GetByID(1); // retrieve one entity by its ID value, this would be acquired dynamically based on some sort of user input rather than hard-coded
var viewModel = new Sites(servers);
viewModel.TTSite = ttSite;
return View(viewModel);
}
I'm not including anything regarding making drop-downs, just illustrating getting data into a view model and then creating a view with that view model.
Note that you would not use the Sites class as an entity but rather a view model, and setting its data based on entities from your database. You wouldn't be setting any primary keys in a view model class; those are the concern of the data model, and you've presumably already got those entities (such as TTSite) set up in a usable fashion in your data layer.
Once you've got a controller action and a view up and working, you can turn to getting the view model data into a form usable by a drop-down list, and going from there.

In MVC do partial views inherit the models of their Parent views?

I'm passing some data to a View from my controller, which I wish to display inside a partial view inside that View (don't ask, it's complicated). I know I probably shouldn't even be passing a model to a view that's inded for another view, but I've noticed that the partial view is actually inheriting the Model from the parenmt View:
public ActionResult Index(){
Person p = new Person
{
FName = "Mo",
LName = "Sep"
};
return View(p);
}
Then inside my Index View I have:
<h2>Index</h2>
#Html.Partial("_IndexPartial")
and Inside _IndexPartial I have:
#Model.FName
and this Prints "Mo".
Is this behaviour intended like that in WPF where child controls inherit the data context of their parent View? And is it considered bad practise to use this in your application?
Thanks.
Is this behaviour intended like that in WPF where child controls
inherit the data context of their parent View?
Yes.
I see you are not currently passing any model to the
Would it work to just inherit the layouts, and then not need to use the partial at all?
If you want to keep using it like you are, maybe just be more explicit about it, and pass the current model to the partial.
#Html.Partial("_IndexPartial", Model)
If you look at the source for Html.Partial(view):
public static MvcHtmlString Partial(this HtmlHelper htmlHelper, string partialViewName)
{
return Partial(htmlHelper, partialViewName, null /* model */, htmlHelper.ViewData);
}
It is passing the model via htmlHelper.ViewData, you can access the model in the same way in your view with #{ViewData.Model}, but this is NOT a good practice.
You can pass the model into the partial view as a second parameter using the overload:
#Html.Partial("viewname", Model)
Nothing wrong with this approach IMO as its the whole point in strongly-typed views and the benefits they bring...

mvc and partials is this not breaking the mvc pattern?

I have a partial view that displays a search options like search by category, region, date etc. This exists on every page. The partial uses a viewmodel containing lists of regions, cats etc.
As this is being used on every page - I have to load these properties on the viewmodel in every action in my controllers to ensure the data is available to the partial view. Not that happy with that. (Have simply used inherited viewmodels)
I see the partial can call a renderaction method on the controller to get the data, but now I would have a view calling data from a controller - breaking the mvc pattern.
what are other people doing in this situation?
You can use custom ActionFilters to inject common functionality to your actions/controllers to avoid repeating the same code.
For example :
public class RequiresSearchOptions : ActionFilterAttribute {
public override void OnResultExecuting(ResultExecutingContext filterContext){
filterContext.Controller.ViewData["SearchOptions"] =
GetSearchOptions();
//Or manipulate the model :
//YourViewModel m =
// (YourViewModel)filterContext.Controller.ViewData.Model;
//m.SearchOptions = GetSearchOptions();
}
}
And then decorate your actions/controllers.
[RequiresSearchOptions]
public ActionResult Index() {
return View();
}
//or
[RequiresSearchOptions]
public class HomeController : Controller {
//Actions
}
For a while I have used partial requests to render reused widgets. In my opinion they are are a more MVC way of rendering widgets over RenderAction as they don't require the View to know what action is being called.
My partial requests render partial views so your existing code can be easily migrated. They can also be output cached in the same way as any asp.net mvc action.
Hope this helps.

Provide user object to every view

How can I provide a user object to every view in ASP.NET MVC without having to create a ViewModel for absolutely every view I have?
When using ASP.NET Membership, I just get a Profile variable in the views with the profile information, but when rolling my own I don't see a way to export that information.
Inherit your controllers from base controller. In base controller override OnActionExecuting and set ViewData["UserObject"] here. Something like this:
public class YourBaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Controller.ViewData["UserObject"] = ...
}
}
Or create custom filter with the same OnActionExecuting method if you want only certain controllers providing user object to View.
UPDATED:
Create custom Html helper if you dont want to cast ViewData["UserObject"] every time:
public static object RenderUserObject(this HtmlHelper html)
{
return ((html.ViewData["UserObject"] as UserObject) ?? new UserObject()).ToString();
}
Inherit your ViewModel classes from a master ViewModel with a User property.
Alternatively, you can pass the object in ViewData collection and use an extension method to make it easy to access the object in the view.
One alternative to having a base ViewModel class, and so having to define a ViewModel class for every view, is to create a generic ViewModel<T> class which exposes a property T InnerModel, or something similar. Then you can pass a ViewModel<Foo> rather than having to explicitly create a FooViewModel class.
Of course if you also need more bespoke ViewModels in places, you can keep the ViewModel base class, and have ViewModel<T> and your bespoke ViewModels extend it.

ViewModel Best Practices

From this question, it looks like it makes sense to have a controller create a ViewModel that more accurately reflects the model that the view is trying to display, but I'm curious about some of the conventions.
Basically, I had the following questions:
I normally like to have one class/file. Does this make sense with a ViewModel if it is only being created to hand off data from a controller to a view?
If a ViewModel does belong in its own file, and you're using a directory/project structure to keep things separate, where does the ViewModel file belong? In the Controllers directory?
That's basically it for now. I might have a few more questions coming up, but this has been bothering me for the last hour or so, and I can seem to find consistent guidance elsewhere.
EDIT:
Looking at the sample NerdDinner app on CodePlex, it looks like the ViewModels are part of the Controllers, but it still makes me uncomfortable that they aren't in their own files.
I create what I call a "ViewModel" for each view. I put them in a folder called ViewModels in my MVC Web project. I name them after the controller and action (or view) they represent. So if I need to pass data to the SignUp view on the Membership controller I create a MembershipSignUpViewModel.cs class and put it in the ViewModels folder.
Then I add the necessary properties and methods to facilitate the transfer of data from the controller to the view. I use the Automapper to get from my ViewModel to the Domain Model and back again if necessary.
This also works well for composite ViewModels that contain properties that are of the type of other ViewModels. For instance if you have 5 widgets on the index page in the membership controller, and you created a ViewModel for each partial view - how do you pass the data from the Index action to the partials? You add a property to the MembershipIndexViewModel of type MyPartialViewModel and when rendering the partial you would pass in Model.MyPartialViewModel.
Doing it this way allows you to adjust the partial ViewModel properties without having to change the Index view at all. It still just passes in Model.MyPartialViewModel so there is less of a chance that you will have to go through the whole chain of partials to fix something when all you're doing is adding a property to the partial ViewModel.
I will also add the namespace "MyProject.Web.ViewModels" to the web.config so as to allow me to reference them in any view without ever adding an explicit import statement on each view. Just makes it a little cleaner.
Separating classes by category (Controllers, ViewModels, Filters etc.) is nonsense.
If you want to write code for the Home section of your website (/) then create a folder named Home, and put there the HomeController, IndexViewModel, AboutViewModel, etc. and all related classes used by Home actions.
If you have shared classes, like an ApplicationController, you can put it at the root of your project.
Why separate things that are related (HomeController, IndexViewModel) and keep things together that have no relation at all (HomeController, AccountController) ?
I wrote a blog post about this topic.
I keep my application classes in a sub folder called "Core" (or a seperate class library) and use the same methods as the KIGG sample application but with some slight changes to make my applications more DRY.
I create a BaseViewData class in /Core/ViewData/ where I store common site wide properties.
After this I also create all of my view ViewData classes in the same folder which then derive from BaseViewData and have view specific properties.
Then I create an ApplicationController that all of my controllers derive from. The ApplicationController has a generic GetViewData Method as follows:
protected T GetViewData<T>() where T : BaseViewData, new()
{
var viewData = new T
{
Property1 = "value1",
Property2 = this.Method() // in the ApplicationController
};
return viewData;
}
Finally, in my Controller action i do the following to build my ViewData Model
public ActionResult Index(int? id)
{
var viewData = this.GetViewData<PageViewData>();
viewData.Page = this.DataContext.getPage(id); // ApplicationController
ViewData.Model = viewData;
return View();
}
I think this works really well and it keeps your views tidy and your controllers skinny.
A ViewModel class is there to encapsulate multiple pieces of data represented by instances of classes into one easy to manage object that you can pass to your View.
It would make sense to have your ViewModel classes in their own files, in the own directory. In my projects I have a sub-folder of the Models folder called ViewModels. That's where my ViewModels (e.g. ProductViewModel.cs) live.
There are no good place to keep your models in. You can keep them in separate assembly if the project is big and there are a lot of ViewModels (Data Transfer Objects). Also you can keep them in separate folder of the site project. For example, in Oxite they are placed in Oxite project which contains a lot of various classes too. Controllers in Oxite are moved to separate project and views are in separate project too.
In CodeCampServer ViewModels are named *Form and they are placed in UI project in Models folder.
In MvcPress project they are placed in Data project, which also contains all code to work with database and a bit more (but I didn't recommend this approach, it's just for a sample)
So you can see there are many point of view. I usually keep my ViewModels (DTO objects) in the site project. But when I have more than 10 models I prefer to move them to separate assembly. Usually in this case I'm moving controllers to separate assembly too.
Another question is how to easily map all data from model to your ViewModel. I suggest to have a look at AutoMapper library. I like it very much, it does all dirty work for me.
And I also I suggest to look at SharpArchitecture project. It provides very good architecture for projects and it contains a lot of cool frameworks and guidances and great community.
here's a code snippet from my best practices:
public class UserController : Controller
{
private readonly IUserService userService;
private readonly IBuilder<User, UserCreateInput> createBuilder;
private readonly IBuilder<User, UserEditInput> editBuilder;
public UserController(IUserService userService, IBuilder<User, UserCreateInput> createBuilder, IBuilder<User, UserEditInput> editBuilder)
{
this.userService = userService;
this.editBuilder = editBuilder;
this.createBuilder = createBuilder;
}
public ActionResult Index(int? page)
{
return View(userService.GetPage(page ?? 1, 5));
}
public ActionResult Create()
{
return View(createBuilder.BuildInput(new User()));
}
[HttpPost]
public ActionResult Create(UserCreateInput input)
{
if (input.Roles == null) ModelState.AddModelError("roles", "selectati macar un rol");
if (!ModelState.IsValid)
return View(createBuilder.RebuildInput(input));
userService.Create(createBuilder.BuilEntity(input));
return RedirectToAction("Index");
}
public ActionResult Edit(long id)
{
return View(editBuilder.BuildInput(userService.GetFull(id)));
}
[HttpPost]
public ActionResult Edit(UserEditInput input)
{
if (!ModelState.IsValid)
return View(editBuilder.RebuildInput(input));
userService.Save(editBuilder.BuilEntity(input));
return RedirectToAction("Index");
}
}
We throw all of our ViewModels in the Models folder (all of our business logic is in a separate ServiceLayer project)
Personally I'd suggest if the ViewModel is anything but trivial then use a separate class.
If you have more than one view model then I suggest it make sense to partition it in at least a directory. if the view model is later shared then the name space implied in the directory makes it easier to move to a new assembly.
In our case we have the Models along with the Controllers in a project separate from the Views.
As a rule of thumb, we've tried to move and avoid most of the ViewData["..."] stuff to the ViewModel thus we avoid castings and magic strings, which is a good thing.
The ViewModel as well holds some common properties like pagination information for lists or header information of the page to draw breadcrumbs and titles. At this moment the base class holds too much information in my opinion and we may divide it in three pieces, the most basic and necessary information for 99% of the pages on a base view model, and then a model for the lists and a model for the forms that hold specific data for that scenarios and inherit from the base one.
Finally, we implement a view model for each entity to deal with the specific information.
code in the controller:
[HttpGet]
public ActionResult EntryEdit(int? entryId)
{
ViewData["BodyClass"] = "page-entryEdit";
EntryEditViewModel viewMode = new EntryEditViewModel(entryId);
return View(viewMode);
}
[HttpPost]
public ActionResult EntryEdit(Entry entry)
{
ViewData["BodyClass"] = "page-entryEdit";
#region save
if (ModelState.IsValid)
{
if (EntryManager.Update(entry) == 1)
{
return RedirectToAction("EntryEditSuccess", "Dictionary");
}
else
{
return RedirectToAction("EntryEditFailed", "Dictionary");
}
}
else
{
EntryEditViewModel viewModel = new EntryEditViewModel(entry);
return View(viewModel);
}
#endregion
}
code in view model:
public class EntryEditViewModel
{
#region Private Variables for Properties
private Entry _entry = new Entry();
private StatusList _statusList = new StatusList();
#endregion
#region Public Properties
public Entry Entry
{
get { return _entry; }
set { _entry = value; }
}
public StatusList StatusList
{
get { return _statusList; }
}
#endregion
#region constructor(s)
/// <summary>
/// for Get action
/// </summary>
/// <param name="entryId"></param>
public EntryEditViewModel(int? entryId)
{
this.Entry = EntryManager.GetDetail(entryId.Value);
}
/// <summary>
/// for Post action
/// </summary>
/// <param name="entry"></param>
public EntryEditViewModel(Entry entry)
{
this.Entry = entry;
}
#endregion
}
projects:
DevJet.Web ( the ASP.NET MVC web
project)
DevJet.Web.App.Dictionary ( a
seperate Class Library project)
in this project, i made some folders like:
DAL,
BLL,
BO,
VM (folder for view models)
Create a view model base class which has commonly required properties like result of the operation and contextual data ,you can also put current user data and roles
class ViewModelBase
{
public bool HasError {get;set;}
public string ErrorMessage {get;set;}
public List<string> UserRoles{get;set;}
}
In base controller class have a method like PopulateViewModelBase() this method will fill up the contextual data and user roles.
The HasError and ErrorMessage , set these properties if there is exception while pulling data from service/db. Bind these properties on view to show error.
User roles can be used to show hide section on view based on roles.
To populate view models in different get actions , it can be made consistent by having base controller with abstract method FillModel
class BaseController :BaseController
{
public PopulateViewModelBase(ViewModelBase model)
{
//fill up common data.
}
abstract ViewModelBase FillModel();
}
In controllers
class MyController :Controller
{
public ActionResult Index()
{
return View(FillModel());
}
ViewModelBase FillModel()
{
ViewModelBase model=;
string currentAction = HttpContext.Current.Request.RequestContext.RouteData.Values["action"].ToString();
try
{
switch(currentAction)
{
case "Index":
model= GetCustomerData();
break;
// fill model logic for other actions
}
}
catch(Exception ex)
{
model.HasError=true;
model.ErrorMessage=ex.Message;
}
//fill common properties
base.PopulateViewModelBase(model);
return model;
}
}

Resources