When is TempData constructed in WebViewPage<TModel> - asp.net-mvc

In a class derived from WebViewPage<TModel> (say MyCustomWebViewPage) that is used as a base class of all views in an MVC application, I am creating and initializing another class that needs ViewData and TempData. My first attempt was to construct this class in constructor of MyCustomWebViewPage. While ViewData is constructed by that time, TempData is not (it is null). I looked for some other method I could override, may be ConfigurePage or InitializePage but none of them are virtual. So, for now, I implemented delayed construction of this class. Curious to know when TempData is constructed and if there is another method that can be overridden.

Related

ActionFilterAttribute ninject injection - DbContext has been disposed

I have my project which uses the usual Repository pattern with Services and Unit of Work (all with Ninject injecting the dependencies from a NinjectModule), but I'm trying to access a service from an ActionFilterAttribute to inject some information (from DB) in the layout of the pages I show so I don't need to mess with all the actions on each controller.
The problem comes when I save to DB on one screen and move to the next and then come back to the previous (with a standard #Url.Action): The ActionFilterAttribute for the Index action is triggered but the call to the service and corresponding repository (within the attribute) throw an exception because the DbContext has been disposed.
Is there any problem with accessing a service and, consequently, the DbContext from an ActionFilterAttribute while injecting the service via Property Injection? I want to make a note that I use property injection for the service in the attribute because the constructor receives 2 parameters that are arbitrary depending on the signature of the Action methods, so my only option was to inject via property.
Let me know if you need some code and I'll update the question.
I found the solution to my problem in the following question:
Injecting dependencies into ASP.NET MVC 3 action filters. What's wrong with this approach?
Combining Mark Seeman's answer with striplingwarrior's comment was the solution to it.
Basically I splitted my ActionFilterAttribute into an Attribute that merely decorated my Actions and keeps the parameters I need for later, and also into an ActionFilter that checked the Action's custom attributes and if my attribute exists, then it injects the data I wanted from the DB into the ViewBag. Everything is later binded with the BindFilter extension from Ninject so it applies only to the methods it needs.

Does ASP.NET MVC allow private ViewModel constructor?

The question is, as in title, whether the MVC model binder allow private constructors for the view model objects. Apparently it doesn't, saying MissingMethodException: No parameterless constructor defined for this object. even if there is a private parameterless constructor.
In case if there is no private constructor allowed, is there an arhitectural workaround?
Such constructor might be useful to ensure that only the model binder could create ViewModel objects whose fields might not be consistently filled - there would be no chance that in other parts of code some fields are forgotten to complete.
Entity Framework, in a similar situation, can use private constructor and private properties.
No, it does not.
If you want to prevent actual code from calling that constructor, you can add [Obsolete("For model binding only", true)] to a public constructor. This will cause a compiler error if the constructor is explicitly called.
You can always write a custom model binder that does support private/protected ctors.

Partially mocking an ASP.Net MVC action method in Rhino Mock?

I'm new to Rhino, and wondered how to mock a local variable/object inside a method of a class I'd also be mocking. In this case I'd be doing it with an ASP.Net MVC controller & action method.
Here's what the controller looks like, simplified:
public class HomeController : Controller {
public myObjectType myMockedObject; //I want to mock this
public myNonMockedObject; //don't want to mock this
public ViewResult Index() {
//call various methods on the mocked and nonmocked members
return View();
}
}
In other words, I'd like to create a mock home controller and mock some local variables within it and their methods-- but not all of them. Is this possible using Rhino?
You can inject these through constructor parameters. Just write constructor that takes myObjectType as parameter. Within this constructor just initialize your fields.
Note1: in case to run MVC, you will need also parameterless ctro, or modify ConstructorFactory (e.g. here https://www.codeproject.com/Articles/560798/ASP-NET-MVC-Controller-Dependency-Injection-for-Be). Or just think about using some IoC container (e.g. https://www.nuget.org/packages/Unity/) that can inject whatever you want inside the controller (mock or normal class).
Note2: you should extract an interface from myObjectType class and mock that interface instead of concrete class (Rhino handles that better).
Note3: I am usually trying to put all the logic (and test that separately) outside of controller since it is quite tough to test the controller (you need to initialize a lot of stuff there what involves another mocking).

BindModel returns null when binding to a list/collection (but not when binding to csla collection)

I have a custom model binder that inherits the DefaultModelBinder that looks like this.
Public Class GridFormBinder : Inherits DefaultModelBinder
Public Overrides Function BindModel(controllerContext As System.Web.Mvc.ControllerContext, bindingContext As System.Web.Mvc.ModelBindingContext) As Object
Dim result As Object = MyBase.BindModel(controllerContext, bindingContext)
'Code to handle special case for grid/List binding.
Return result
End Function
End Class
The reason I have this custom binder is that I am presenting various list of items in a grid (using devexpress mvc gridview) and I bind the controls in the grid to the list of items.
If I use a class derived from BusinessCollectionBase (from a very modified CSLA framework class) everything works exactly like I want. BusinessCollectionBase derives from a class that looks like...
<Serializable()> Public MustInherit Class BindableCollectionBase(Of T As IBusinessData)
Inherits CollectionBase
Implements IBindingList
Implements System.Collections.Generic.IEnumerable(Of T)
But if I bind to, say, a class that inherits from BindingList<Customer> the MyBase.BindModel(controllerContext, bindingContext) always returns nothing. I have tried various generic and non-generic BCL collections and the BindModel method always returns null.
Is there something I have to do to get the DefaultModelBinder to create and return the model for regular collections?
I looked at the source for DefaultModelBinder and figured out the problem.
In the DefaultModelBinder in the BindComplexModel method if the type is not an array and is a generic IEnumerable ( IEnumerable<>) AND it is an instance of ICollection<> it will call UpdateCollection. It cannot populate the collection for all the reasons stated. Because the count = 0 the UpdateCollection method returns null. So my classes that derive from ICollection (BindingList for example) will have this behavior.
However my custom collection actually derives from the old CollectionBase class (and it implements the generic IEnumerable seperatly). This means that BindComplexModel does not try to populate the collection and instead just binds to the object as normal.*
Personally I think this is a bug or at least an oversight. If you are binding to a collection and the form has 0 items (say the user has deleted all the rows) you would get nothing back from the default binding. But shouldn't you just get the collection with zero items? What is the reasoning behind returning nothing? This puts more work on the MVC developer because now they have to check for nothing first.
But anyway this is the reason why.
*And this is also the reason I couldn't get the examples of binding to collections to work with my classes. They are not arrays but neither are they IEnumerable<> or IDictionary<>. Yet another bug I think.

ASP.NET MVC: Criteria for controller's method to be an action?

I'm writing some unit tests to assert that all our controller action methods are marked with proper custom attributes, but I don't really know what the criteria is for determining whether a public method can act as MVC action or not.
I would assume that a criteria could be the return value type (it has to be ActionResult or a derivative). Is this true? What about static methods?
For a method to be considered an action, it has to meet the following criteria:
It must be public and not static
It must not have a "special" name in order to exclude constructors, events etc.
It must not be defined on System.Web.Mvc.Controller or any other base class in order to exclude .ToString() and family.
Generic methods will throw an exception, yet for some reason they are considered actions. As for the return type, it does not necessarily have to be an ActionResult, since you can return e.g. a string for text data.
I beleive all public methods in a controller are treated as actions - even one returning a string.
Determining the true list of actions on a controller is a tricky problem. The only correct answer is that it "depends"! The list that Saulius gave is pretty much correct - if you're using the default ControllerActionInvoker - which of course, most people use.
If you want to avoid duplicating the logic I would recommend using the ControllerActionInvoker itself to get the list of actions and then verify the contents of the list that it returns.
You'll have to write a class that derives from ControllerActionInvoker so that you can call the GetControllerDescriptor() method. The return value of that method is a ControllerDescriptor, which is an abstract descriptor of what the controller has. You can then call GetCanonicalActions(), which returns a list of ActionDescriptors. Each of those items represents what is typically and action method.
To hook it all up you'll need to:
Instantiate your controller
Set its ActionInvoker property to be an instance of your custom invoker
Create a ControllerContext instance that has its Controller instance set to your controller
Call a new public method on your invoker that in turn calls GetControllerDescriptor()
Then verify the results and you're done!
Of course, I haven't tried any of this but in theory it all works :)

Resources