Pass subclass of generic model to razor view - asp.net

The Big Picture:
I have found what seems like a limitation of Razor and I am having trouble coming up with a good way around it.
The Players:
Let's say I have a model like this:
public abstract class BaseFooModel<T>
where T : BaseBarType
{
public abstract string Title { get; } // ACCESSED BY VIEW
public abstract Table<T> BuildTable();
protected Table<T> _Table;
public Table<T> Table // ACCESSED BY VIEW
{
get
{
if (_Table == null)
{
_Table = BuildTable();
}
return _Table;
}
}
}
And a subclass like this:
public class MyFooModel : BaseFooModel<MyBarType>
{
// ...
}
public class MyBarType : BaseBarType
{
// ...
}
I want to be able to pass MyFooModel into a razor view that is defined like this:
// FooView.cshtml
#model BaseFooModel<BaseBarType>
But, that doesn't work. I get a run-time error saying that FooView expects BaseFooModel<BaseBarType> but gets MyFooModel. Recall that MyFooModel in herits from BaseFooModel<MyBarType> and MyBarType inherits from BaseBarType.
What I have tried:
I tried this out in non-razor land to see if the same is true, which it is. I had to use a template param in the View to get it to work. Here is that non-razor view:
public class FooView<T>
where T : BaseBarType
{
BaseFooModel<T> Model;
public FooView(BaseFooModel<T> model)
{
Model = model;
}
}
With that structure, the following does work:
new FooView<MyBarType>(new MyFooModel());
My Question:
How can I do that with Razor? How can I pass in a type like I am doing with FooView?
I can't, but is there any way around this? Can I achieve the same architecture somehow?
Let me know if I can provide more info. I'm using .NET 4 and MVC 3.
EDIT:
For now, I am just adding a razor view for each subclass of BaseFooModel<BaseBarType>. I'm not psyched about that because I don't want to have to create a new view every time I add a new model.
The other option is to just take advantage of the fact that I am able to get this working in regular c# classes without razor. I could just have my razor view #inherits the c# view and then call some render method. I dislike that option because I don't like having two ways of rendering html.
Any other ideas? I know its hard to understand the context of the problem when I'm giving class names with Foo and Bar, but I can't provide too much info since it is a bit sensitive. My apologies about that.
What I have so far, using Benjamin's answer:
public interface IFooModel<out T>
where T : BaseBarModel
{
string Title { get; }
Table<T> Table { get; } // this causes an error:
// Invalid variance: The type parameter 'T' must be
// invariantly valid on IFooModel<T>.Table.
// 'T' is covariant.
}
public abstract class BaseFooModel<T> : IFooModel<T>
where T : BaseBarModel
{
// ...
}
What ended up working:
public interface IFooModel<out T>
where T : BaseBarModel
{
string Title { get; }
BaseModule Table { get; } // Table<T> inherits from BaseModule
// And I only need methods from BaseModule
// in my view.
}
public abstract class BaseFooModel<T> : IFooModel<T>
where T : BaseBarModel
{
// ...
}

You need to introduce an interface with a covariant generic type parameter into your class hierarchy:
public interface IFooModel<out T> where T : BaseBarType
{
}
And derive your BaseFooModel from the above interface.
public abstract class BaseFooModel<T> : IFooModel<T> where T : BaseBarType
{
}
In your controller:
[HttpGet]
public ActionResult Index()
{
return View(new MyFooModel());
}
Finally, update your view's model parameter to be:
#model IFooModel<BaseBarType>

Using interfaces-based models was deliberately changed between ASP.NET MVC 2 and MVC 3.
You can see here
MVC Team:
Having interface-based models is not something we encourage (nor, given the limitations imposed by the bug fix, can realistically support). Switching to abstract base classes would fix the issue.
"Scott Hanselman"

The problem you are experiencing is not a Razor error, but a C# error. Try to do that with classes, and you'll get the same error. This is because the model is not BaseFooModel<BaseBarType>, but BaseFooModel<MyFooModel>, and an implicit conversion cannot happen between the two. Normally, in a program you'd have to do a conversion to do that.
However, with .NET 4, introduced was contravariance and covariance, which sounds like the ability of what you are looking for. This is a .NET 4 feature only, and I honestly don't know if Razor in .NET 4 makes use of it or not.

Related

Handling specimen creation inconsistencies between AutoFixture and Moq

I am using AutoMoqCustomization in my test conventions.
Consider the code below. Everything works great until I add a constructor to one of the concrete classes. When I do, I get "could not find a parameterless constructor". We know AutoFixture doesn't have an issue with the constructor because it delivered me the test object one which proved to be assignable from IThings... no failure there. So it must be moq.
This makes some sense because I assume builder was generated by moq and passed into the GetCommands method. So I think I can see that control has been passed from AutoFixture to moq at that point.
That takes care of the why, but what should I do about it? Is there a way to instruct moq on how to deal with the ThingOne or is there a way to instruct AutoFixture to ignore moq for IThingBuilders and instead do something Fixtury?
public class TestClass
{
public interface IThingBuilders
{
T1 Build<T1>() where T1 : IThings;
}
public interface IThings
{
}
public class ThingOne : IThings
{
public ThingOne(string someparam)
{
}
}
public class ThingTwo : IThings
{
}
public class SomeClass
{
public List<IThings> GetCommands(IThingBuilders builder)
{
var newlist = new List<IThings>();
newlist.Add(builder.Build<ThingOne>());
newlist.Add(builder.Build<ThingTwo>());
return newlist;
}
}
[Theory, BasicConventions]
public void WhyCannotInstantiateProxyOfClass(ThingOne one, ThingTwo two, IThingBuilders builder, SomeClass sut)
{
Assert.IsAssignableFrom<IThings>(one);
Assert.IsAssignableFrom<IThings>(two);
var actual = sut.GetCommands(builder);
Assert.Equal(1, actual.OfType<ThingOne>().Count());
Assert.Equal(1, actual.OfType<ThingTwo>().Count());
}
}
As there's no extensibility point in Moq that enables AutoFixture to hook in and supply a value of ThingOne, there's not a whole lot you can do.
However, you can use the SetReturnsDefault<T> method of Moq. Modifying the above test would then be like this:
[Theory, BasicConventions]
public void WhyCannotInstantiateProxyOfClass(
ThingOne one, ThingTwo two, IThingBuilders builder, SomeClass sut)
{
Assert.IsAssignableFrom<IThings>(one);
Assert.IsAssignableFrom<IThings>(two);
Mock.Get(builder).SetReturnsDefault(one); // Add this to make the test pass
var actual = sut.GetCommands(builder);
Assert.Equal(1, actual.OfType<ThingOne>().Count());
Assert.Equal(1, actual.OfType<ThingTwo>().Count());
}
This is a bit easier than having to write a specific Setup/Returns pair, but not much. You could move that code to an AutoFixture Customization, but again, since this is a generic method on a a Mock instance, you'll explicitly need to call this for e.g. ThingOne in order to set the default for that return type. Not particularly flexible.

Inserting data using Linq C# with MVC 3 Architecture in asp.net

I m inserting data using controller,
SignUpcontroller.cs
[HttpPost]
public ActionResult Index(SignUpModel sm)
{
using(DataClassesDataContext dc= new DataClassesDataContext())
{
Dummytable dm= new Dummytable();
{
dm.Name=sm.password;
}
//then conncetion string and submit
}
}
and redirection
My question is, is it correct to write this code in the controller module or do i need to write it in models module, if i need to write it in models module then how to define the setter help me out
It is better practice to move all data access code in a data access layer. So simply put this code in a separate class that you could reference and call from your controller. For example you could define an interface that will define the different operations:
public interface IRepository
{
void Insert(SignUpModel model);
}
and then have a specific implementation that is working with the data access technology you are using (EF for example):
public class RepositoryEF : IRepository
{
public void Insert(SignUpModel model)
{
using(DataClassesDataContext dc= new DataClassesDataContext())
{
Dummytable dm = new Dummytable();
dm.Name = sm.password;
}
}
}
and the next step is to have your controller take this repository as constructor dependency:
public class SomeController : Controller
{
private readonly IRepository repo;
public SomeController(IRepository repo)
{
this.repo = repo;
}
[HttpPost]
public ActionResult Index(SignUpModel sm)
{
this.repo.Insert(sm);
...
}
}
Now all that's left is pick up some DI framework and wire up the dependencies.
This way you have a clear separation between your controller logic and the data access layer. This would allow you to unit test the various layers of your application in separation.
first question is Where is your DataAccessLayer ?
So the better practise is write the codes in another one class for read and write database values .
The controller have only for UI logics
and you can use Interface for increase reusability reason and Unit Testing .
This is not common to use for vital data storing/accessing like signup. Consider web security tools and don't work directly with this type of data. Or change your meaning to work with common data.
for the Implementation to work i jst give memory of class to interface with the help of casting from the controller
[HttpPost]
public ActionResult Index(SignUpModel sm)
{
ISignUpModel ISign= (ISignUpModel)this.sm;
ISign.Insert(sm);
}
thanks everyone else, because of you all i learn this :)
and at the SignUpModel.cs, is normal "Interface named as ISignUp with Insert method" Implementation

How to share a common object in each page request of a ASP.net MVC 4 webapp?

I come from "regular" asp.net so i'm a bit (totally) lost with MVC.
What I was doing with my own asp.net programmation pattern :
I have one custom class objet which represent the "page" and its properties (like mypage.loadJquery, mypage.isLogged, mypage.Title, custom cache logic, etc.)
This class is instanciate once on top of each ASHX page, I then manipulate a stringbuilder to produce HTML and spit it right at the browser at the end.
Having only one request on the ASHX page, i can use my page object instanciated at the top till the end when calling final response.write
Now i'm trying to go for MVC. I "kind of" understood the M/V/C model and the routing concept. I would like to keep my custom "page" object but I lost my page life cycle and I definitely don't know how to instanciate my page object ONCE in at the top of every call.
I need this instanciated ONCE shared object across every models, controllers, views, partial views, htmlhelper...
I realize MVC pattern might be confusing for me at this moment, bu how could I try to reproduce my need ?
(Very concrete exemple : On every request i need to check if the user is logged via his cookies. If it is I round trip the database to get user infos. Then I DO NEED THESE INFOS ON PRATICALLY EVERY model / controller / view of the app, but of course don't want to round back each time to security check and database querying, how can i have these info on the whole mvc cyle ?)
In my project I create interface IViewModel that contains all fields that I need in my layout/masterpage and set is as model of it so I can easily use them:
IViewModel.cs
public interface IViewModel
{
string Title { get; set; }
User User { get; set; }
}
Layout.cshtml
#model IViewModel
<html>
<head>
<title>#Model.Title</title>
</head>
<body>
#if (Model.User.IsAuthenticated) {
You are logged as #Model.User.Name
}
</body>
</html>
All my models implement that interface (or inherit from ViewModelBase that is default implementation of that class). Additionally I have custom action filter that check if returned ActionResult is (Partial)ViewResult and if Model of it implement my IViewModel interface and fill data in that interface.
public FillViewModelAttribute : ActionFilterAttribute
{
public override OnActionExecuted(ActionExecutedContext context)
{
var viewResult = context.Result as ViewResult;
if (viewResult != null && viewResult.Model is IViewModel)
{
var viewModel = (IViewModel)viewResult.Model;
// fill data
}
}
}
I created many projects like this. Basically, you can create a base controller class where all the other controllers inherit from it.
[Authorize]
public class BaseController : Controller
{
private Instructor _G_USER = null;
protected Instructor G_USER
{
get
{
if (_G_USER == null)
{
_G_USER = Your DB query here
ViewData["G_USER"] = _G_USER;
}
return _G_USER;
}
}
}
Then in your every child class, you can do
[Authorize]
public class YourController : BaseController
{
public ActionResult Index()
{
if(!G_USER.CAN_DO_THIS) throw new NoPermissionException();
return View();
}
}
To use the User in the view, create an extension method.
public static class ExtentionMethods
{
public static USER G_USER(this ViewPage page)
{
return (USER)page.ViewData["G_USER"];
}
}
Then use in the page like this
<%=this.G_USER().....%>

Best way to do global viewdata in an area of my ASP.NET MVC site?

I have an several controllers where I want every ActionResult to return the same viewdata. In this case, I know I will always need basic product and employee information.
Right now I've been doing something like this:
public ActionResult ProductBacklog(int id) {
PopulateGlobalData(id);
// do some other things
return View(StrongViewModel);
}
Where PopulateGlobalData() is defined as:
public void PopulateGlobalData(int id) {
ViewData["employeeName"] = employeeRepo.Find(Thread.CurrentPrincipal.Identity.Name).First().FullName;
ViewData["productName"] = productRepo.Find(id).First().Name;
}
This is just pseudo-code so forgive any obvious errors, is there a better way to be doing this? I thought of having my controller inherit a class that pretty much does the same thing you see here, but I didn't see any great advantages to that. It feels like what I'm doing is wrong and unmaintable, what's the best way to go about this?
You could write a custom action filter attribute which will fetch this data and store it in the view model on each action/controller decorated with this attribute.
public class GlobalDataInjectorAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
string id = filterContext.HttpContext.Request["id"];
// TODO: use the id and fetch data
filterContext.Controller.ViewData["employeeName"] = employeeName;
filterContext.Controller.ViewData["productName"] = productName;
base.OnActionExecuted(filterContext);
}
}
Of course it would much cleaner to use a base view model and strongly typed views:
public class GlobalDataInjectorAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
string id = filterContext.HttpContext.Request["id"];
// TODO: use the id and fetch data
var model = filterContext.Controller.ViewData.Model as BaseViewModel;
if (model != null)
{
model.EmployeeName = employeeName;
model.ProductName = productName;
}
base.OnActionExecuted(filterContext);
}
}
Now all that's left is to is to decorate your base controller with this attribute:
[GlobalDataInjector]
public abstract class BaseController: Controller
{ }
There's another more interesting solution which I personally prefer and which involves child actions. Here you define a controller which handles the retrieval of this information:
public class GlobalDataController: Index
{
private readonly IEmployeesRepository _employeesRepository;
private readonly IProductsRepository _productsRepository;
public GlobalDataController(
IEmployeesRepository employeesRepository,
IProductsRepository productsRepository
)
{
// usual constructor DI stuff
_employeesRepository = employeesRepository;
_productsRepository = productsRepository;
}
[ChildActionOnly]
public ActionResult Index(int id)
{
var model = new MyViewModel
{
EmployeeName = _employeesRepository.Find(Thread.CurrentPrincipal.Identity.Name).First().FullName,
ProductName = _productsRepository.Find(id).First().Name;
};
return View(model);
}
}
And now all that's left is to include this wherever needed (probably the master page if global):
<%= Html.Action("Index", "GlobalData", new { id = Request["id"] }) %>
or if the id is part of the routes:
<%= Html.Action("Index", "GlobalData",
new { id = ViewContext.RouteData.GetRequiredString("id") }) %>
I thought of having my controller inherit a class that pretty much does the same thing you see here, but I didn't see any great advantages to that.
This is the way to go, in my opinion. You'd create a base Controller class that would provide this functionality. If you are familiar with the ASP.NET WebForms model then this is similar to creating a custom base Page class.
As to the advantages of putting it in a base class, the main advantages are readability, maintainability and reusability. If you copy and paste the above method into each controller that needs it, you are going to have a more difficult time if, down the road, you need to add new information to the ViewData collection.
In short, anytime you catch yourself copying and pasting code among classes or views in your application you should stop and think about how to put such logic in a single place. For more, read up on DRY - Don't Repeat Yourself.

How do you pass an arbitrary bit of data to a user control in ASP.NET MVC using Html.RenderPartial()?

I have a strongly typed user control ("partial") and I'd like to be able to pass it some additional information from its containing view. For example, I have view that's bound to a product class and i have a partial that also is strongly typed to that same model, but I also need to pass an additional parameter for imageSize to my partial. I'd like to be able to do something like this:
<% Html.RenderPartial("_ProductImage", ViewData.Model, new { imageSize = 100 }); %>
As far as I know there is no way to do this, but I'm hoping that someone smarter than me may have a solution ;)
Change the type of the partial model:
class PartialModel
{
public int ImageSize { get; set; }
public ParentModelType ParentModel { get; set; }
}
Now pass it:
<% Html.RenderPartial("_ProductImage",
new PartialModel() { ImageSize = 100, ParentModel = ViewData.Model }); %>
Not the most beautiful solution
<% ViewData["imageSize"] = 100; %>
<% Html.RenderPartial("_ProductImage"); %>
the ViewData is passed by default
I use a generic class model - which is similar in concept to the approach suggested by Craig.
I kind of wish MS would create an overload to RenderPartial to give us the same functionality. Just an additional object data parameter would be fine.
Anyway, my approach is to create a PartialModel which uses generics so it can be used for all .ascx controls.
public class PartialControlModel<T> : ModelBase
{
public T ParentModel { get; set; }
public object Data { get; set; }
public PartialControlModel(T parentModel, object data) : base()
{
ParentModel = parentModel;
Data = data;
}
}
The .ascx control should inherit from the correct PartialControlModel if you want the view to be strongly typed, which most likely you do if you've got this far.
public partial class ThumbnailPanel :
ViewUserControl<PartialControlModel<GalleryModel>>
Then you render it like this :
<% Html.RenderPartial("ThumbnailPanel",
new PartialControlModel<GalleryModel>(ViewData.Model, tag)); %>
Of course when you refer to any parent model items you must use this syntax :
ViewData.Model.ParentModel.Images
You can get the data and cast it to the correct type with :
ViewData.Model.Data
If anyone has a suggestion on how to improve the generics I'm using please let me know.

Resources