Does ASP.NET MVC Has Anything Equivalent To WPF's DataTemplate Feature? - asp.net-mvc

In my ASP.NET MVC project, I have a polymorphic collection that I wish to render - say, an IEnumerable<ISomething> where the individual items may be a mix of different implementations of ISomething.
I'd like that list rendered, where each concrete type renders according to its own template (perhaps a strongly typed ViewUserControl).
In WPF, I'd be able to specify DataTemplates that would automatically bind concrete types to specific templates. Can I do something similar in ASP.NET MVC?
Obviously, I can iterate through the list and attempt a cast using the is keyword and then use a lot of if statements to render the desired control, but I was hoping for something more elegant (like WPF).

I ended up with developing a solution myself - I have described it in DataTemplating In ASP.NET MVC.

I'm not sure if I get you fully, but, why don't you implement a method to your ISomething interface like render for example, which by contract will be implemented to all of your other concrete entities, and then iterate through each item in the polymorphic collection and call it.

I had a similar issue and never found a "simple" answer. I had the benefit of knowing that all items in the list would render the same way so I created a decorator for ISomething, converted the list to IEnumerable using some code from the Umbrella project (http://umbrella.codeplex.com), and then extracted out the relevant pieces. Kinda like the following:
public interface ISomethingDecorator
{
string Description { get; }
string[] Actions { get; }
}
public class BigSomethingDecorator : ISomethingDecorator { /* ... */ }
public class SmallSomethingDecorator : ISomethingDecorator { /* ... */ }
Then, as I said, I use the Umbrella project to convert from ISomething to ISomethingDecorator and returned IEnumerable to the View.
Don't know if it'll help you with what you're trying to do -- especially being a month late -- but I thought I'd let you know how I handled it. If you're displaying completely different formats, it probably won't do the trick but maybe it can get you a starting point.

Related

Conditional namespaces in mvc views

I'm working on MVC 3 and using resource files to localize the application. Now we have another customer on board for the application and they would like to change some of the text on the application..typical.
I have create a separated resource file for them and would like to do something like this in views
if (customer =A )
#using Resources.customerA
else
#using Resources.customerB
I've a resource class in both namespaces so something like this works fine if I change the namespace
Resource.WelcomeUser
Is it possible to use conditional using statement in views? I'm unable to find the right syntax for this. Any ideas?
You can put both using statements in View, but when you use classes you would have to write some namespace prefix.
Example:
#using Project.Resources.customerA
#using Project.Resources.customerB
using classes:
customerA.WelcomeUser
customerB.WelcomeUser
I think there is no other way, because two files cannot have the same path.
What you're really talking about is the provider pattern. You have two (or more) interchangeable things, and you want to be able to use one or the other contextually.
The correct way to do this in an OO context is to create and use an interface, while then injecting the actual implementation you want at runtime. You can actually achieve this in ASP.NET Core, which supports injection in Views, but in ASP.NET MVC 5 and previous, you'd need to go a little out of your way. I'm imagining these are currently static classes, since you're referencing them merely via namespace. With that approach, you'd need to follow #Ssheverdin's advice and use the FQN of the class (i.e. with the namespace):
#if (customer == A)
{
#Resources.customerA.StaticClass.Property
}
else
{
#Resources.customerB.StaticClass.Property
}
Alternatively, you could change the static classes to be instance classes and use a factory pattern to return the right one. This is a very simplistic example, but hopefully enough to convey the idea:
public static class ResourceFactory
{
public static IResourceClass GetForCustomer(string customer)
{
switch (customer)
{
case "A":
return new Resources.customerA.ResourceClass();
default:
return new Resources.customerB.ResourceClass();
}
}
Then:
#{ var resource = ResourceFactory.GetForCustomer(customer); }
I have managed to achieve the behaviour by adding a web.config file under views folder and including the namespaces there, i have to remove the #using statement from all views obviously. You might find that intellisense doesn't work anymore for you so try closing all views and reopen them again.
With this way I can create a separate web.config file for each customer and specify the relevant namespaces accordingly. Now just have to make sure to provide the RIGHT config file for each customer when deploying the release:)

Create reuseable UI componets with MVC

I am in the phase of building a rendering framework for rendering my models in different formats.
My idea is the following:
public class ResidenceRendererShort : IRender<Residence> {
public string Format() {
return "short";
}
public string Render(Residence content) {
return content.Name; // Could return a whole lot of HTML
}
}
I can have multiple of those with different formats, and they are all injected using Ninject DI into my RenderingService, where I got methods for finding the correct render, using methods like e.g. FindRendererFor(Type type, string format)
Now my question is, how can I create a tag in razor which will use the rendering service and applying the correct render? I have been looking into HtmlHelpers, but they are static methods and I can not inject my RenderingService into this.
I thought I could create something like:
#Model my.namespace.Residence
#Html.RenderObject(Model, "short");
Am I missing something or someone got an idea on how to accomplish this?
You're killing yourself. Just use Display/Editor Templates. If you have a view in ~/Views/Shared/DisplayTemplates or ~/Views/Shared/EditorTemplates named after your class, Residence.cshtml in this case, then Razor will use this view to render your class whenever it's passed to Html.DisplayFor or Html.EditorFor.

What is the appropriate granularity in building a ViewModel?

I am working on a new project, and, after seeing some of the difficulties of previous projects that didn't provide enough separation of view from their models (specifically using MVC - the models and views began to bleed into each other a bit), I wanted to use MVVM.
I understand the basic concept, and I'm excited to start using it. However, one thing that escapes me a bit - what data should be contained in the ViewModel?
For example, if I am creating a ViewModel that will encompass two pieces of data so they can be edited in a form, do I capture it like this:
public PersonAddressViewModel {
public Person Person { get; set; }
public Address Address { get; set; }
}
or like this:
public PersonAddressViewModel {
public string FirstName { get; set; }
public string LastName { get; set; }
public string StreetName { get; set; }
// ...etc
}
To me, the first feels more correct for what we're attempting to do. If we were doing more fine grain forms (maybe all we were capturing was FirstName, LastName, and StreetAddress) then it might make more sense to go down to that level. But, I feel like the first is correct since we're capturing ALL Person data in the form and ALL Address data. It seems like it doesn't make sense (and a lot of extra work) to split things apart like that.
Appreciate any insight.
If you are using all the fields of the Person object, then there's nothing wrong with using a complex view model. However, if you are only using a field here or there, then it's much better to build your viewmodel with only those values you are using.
You can do your view models any way you like, but the whole point of having them is that a view model should be customized to the view it's representing.
It can also be a lot easier to use the first method if you're using something like AutoMapper to map to business or domain models, because the objects should have similar definitions.
You're not using MVVM. You're defining ViewModels, classes for only view purposes in order to avoid to break the Model classes. In that case you can define the properties you want for your best profit. In the example I will go for the second solution but it's up to you.
I'm working on a big project with many developer providers. In that case the customer let us to define the ViewModels that we want keeping the Models (Business Entities as they call) for their concern. Because we are different groups no one is worried about another ViewModels so you can even use one class for one view, no matter if another view is different a little bit from the first one. That's one of the advantages of ViewModels instead of pure Model using.
I prefer to define the ViewModels in client-side through JSON objects for the sake of data binding. With this you can truly use MVVM through knockoutjs, angularjs, backbonejs, etc....
If you want to use MVVM check knockoutjs. It's very easy and pleasant to use
Using Model classes directly or wrapping them (as in your 1st example) in your ViewModel class can be a potential security issue if your Model classes have some sensitive properties (i.e. IsAdmin in the User class).
Say your controller actions takes a PersonAddressViewModel input parameter:
public ViewResult someAction(PersonAddressViewModel personAddress)
{
//save it
}
A malicious user can basically set any property in your PersonAddressViewModel composite object even if your UI does not provide such capabilitiy.
This is made possible by the default binding mechanism of the MVC.
To avoid this, either don't wrap sensitive model classes or use the Bind attribute
More on this here: Pro ASP.NET MVC 3 Framework 3rd Edition By Steven Sanderson , Adam Freeman (Chapter 17)
If you're using that view model to render a form, I would vote for the second approach, since you're combining all the view data required for the form.

Model - Partial class and Datacontext class are not communicating

I've created a one table contact DB, which has only 3 columns (Id, Name, and Phone). I've then created the ContactsDataContext using my table Contacts in the model folder. Finally, I create a partial class still in the model folder (public partial class Contact).
now when I write this
public partial class Contact
{
public string MyContact
{
get
{
string name = this.Name ?? String.Empty;
}
// ... Other lines omitted
}
}
I get the following error :"'ContactsManager.Models.Contact' does not contain a definition for 'Name' and no extension method 'Name' accepting a first argument of type 'ContactsManager.Models.Contact' could be found (are you missing a using directive or an assembly reference?)"
Is something wrong??? Even the Intellisense in not showing the properties from my DataContext class. Yet, I've written some partial classes in the past with no problem.
Thank you.
Are namespaces the same on the two partials?
Chris Roden,
Yes, I've resolve it. In fact, I've asked the above question many months ago when I started learning ASP.NET MVC. I bought a book called "ASP.NET MVC - The Beer House/Nick Berardi/Wrox." Is a god book, but it's not recommendable for beginners. Generaly, things are thrown like that without telling where they come from.
The response came from applying the definition of a partial class. Among others, partial classes must:
have the same name
be preceded by 'partial' keyword,
be defined in the same namespace,
etc.
If you miss any of the above criteria, then you'll be in trouble because those criteria, ll be used to merge all the partial classes into a unique one.
In my case, I created a table called ContactDB. After I've created the datacontext class, I've dropped the ContactDB table on the Linq2Sql editor. As you must know, that creates the following class:
public partial class ContactDB
{
//All the columns in the table become properties in this class
}
The partial keyword allow me to write this:
public partial class ContactDB
{
//I can reference members of the above partial class... using this keyword
//After all, the 2 constitute one class.
}
After reading the definition of partial classes, I found out that I failed one of the criteria. I called my other partial class "Contact" which's different from ContactDB. That was enough to make me go crazy for 3 days until I read the definition. Moreover, if you defines the partial class with the right name but you put it in a different namespace, you'll get in trouble as well.
So, if the above answer doesn't work for you (I don't know exactly your problem), check the definition of the partial class.Don't forget to read the ScottGu's series on Linq2Sql.
Hope it helps.

Dynamic typed ViewPage

Is this possible? Here's what I'm trying:
public ActionResult Index()
{
dynamic p = new { Name = "Test", Phone = "111-2222" };
return View(p);
}
And then my view inherits from System.Web.Mvc.ViewPage<dynamic> and tries to print out Model.Name.
I'm getting an error: '<>f__AnonymousType1.Name' is inaccessible due to its protection level
So basically, is what I'm trying to do just not possible? Why or why not?
Update: here's my view
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<asp:Content ...>
<%=Model.Name%>
<%=Model.Phone%>
</asp:Content>
The View constructor is built-in to the framework.
Anonymous types cannot be returned by a method; they are only valid within the scope of the method in which they are defined.
You should use a Model class that you have previously defined and pass that to your View. There is nothing wrong with passing a Model class that does not have every field defined.
Update:
I think I was wrong before. This should work. Perhaps the problem is within the View. Can you post more code? Especially the View and its constructor.
Update the Second:
Ok, I was wrong about passing an anonymous type to another method for use as a dynamic variable -- that can be done.
But I was also wrong in my belief that what you're trying to do would work. Unfortunately for you, it will not. The problem is that you are using ViewPage<TModel>, which uses a ViewDataDictionary<TModel> internally. Because they require strong types, you won't be able to use dynamic objects with them. The internal structure just doesn't use dynamic internally, and specifying dynamic as the type fails.
What would be needed is a DynamicViewPage class and corresponding DynamicViewDataDictionary class that accept object and store it internally as a dynamic. Then you could use an anonymous type and pass it to your Views.
That said, you would not gain anything. You would be able to specify your Views as you have done (i.e. <%=Model.Name%>), but you would not benefit from strong typing. There would be no intellisense and there would be no type safety. You'd do just as well to use the untyped ViewDataDictionary as #Dennis Palmer suggests.
This has been an interesting (and, unfortunately for me, absorbing) thought experiment, but I think, ultimately, that it's not going to happen. Either declare a public type and pass it to your Views, or use the untyped dictionary.
What benefit were you hoping to get from using the dynamic type here?
Using the ViewData dictionary is a very easy way of adding arbitrary objects/items to your view output.
You don't need reflection to get the property names within your View. Just use ViewData.Keys to get the collection of names.
Edit: I've just learned a bit more about dynamics myself and I think maybe you need to create your own dynamic object class that inherits from DynamicObject. You'll want to have a private dictionary in that class and then override TrySetMember and TryGetMember.
Edit Aside: I think one advantage of a strongly typed ViewModel is that you can accept it as a parameter in your POST Action methods. The MVC framework will handle the model binding and in the action method you simply have an instance of your ViewModel class. I don't think you'll have that advantage with a dynamic even if they do work.
Edit Result: Well, I tried using a class derived from DynamicObject, but VS2010 crashes when it tries to render the view. I don't get any exception, just a hard crash and Visual Studio restarts. Here's the code I came up with that causes the crash.
The custom dynamic class:
public class DynViewModel : DynamicObject
{
private Dictionary<string, object> ViewDataBag;
public DynViewModel()
{
this.ViewDataBag = new Dictionary<string, object>();
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
this.ViewDataBag[binder.Name] = value;
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = this.ViewDataBag[binder.Name];
return true;
}
}
In the controller:
public ActionResult DynamicView()
{
dynamic p = new DynamicViewModel.Models.DynViewModel();
p.Name = "Test";
p.Phone = "111-2222";
return View(p);
}
My view is basically the same as what is listed in the question:
<p>Name: <%=Model.Name %></p>
<p>Phone: <%=Model.Phone %></p>
My Conclusion: This might work, but in the Beta 1 of VS2010 I can't figure out why my code causes Visual Studio to crash. I'll try it again in VS2010 Beta 2 when it is released because it is an interesting exercise in learning about dynamics. However, even if this were to work, I still don't see any advantage over using the ViewData dictionary.
Phil Haack to the rescue! Here's a blog post by Phil Haack that might help you out. It looks like it is what you were looking for. Fun With Method Missing and C# 4
The actual error here (<>f__AnonymousType1.Name' is inaccessible due to its protection level) is the result of using anonymous types. Anonymous types are implicitly internal (at least in C#), therefore they can only be accessed normally from the same assembly. Since your view is compiled into a separate assembly at runtime, it can't access the internal anonymous type.
The solution is to pass concrete/named classes as models to your view. The view itself can still use dynamic if you want.
On .NET 4.0 Anonymous types can easily be converted to ExpandoObjects and thus all the problems is fixed with the overhead of the conversion itself.
Check out here

Resources