Is there a way to fine tune Autofac MVC3 Action Injection? - asp.net-mvc-3

So I got Action Injection with Autofac implemented in large MVC solution, or so I thought.
Turned out there were cases were it did not work properly.
In one of the views we were posting back manually some extra information, and model binder was able to match it up properly, like here:
public ActionResult SomeAction(string[] textInfo, bool[] boolInfo, SomeViewModel viewModel)
However as soon as I enabled action injection:
builder.RegisterControllers(typeof(MvcApplication).Assembly).InjectActionInvoker();
The first two parameters, are being received as empty arrays.
My hypothesis would be, that autofac figures out, those were not provided, and provides default value for those. Is there any way to work around this behavior? With some parameter-level attribute perhaps?

Related

Problems with Spring Forms and Validation

I am newer to Spring, previously I've worked in PHP and Python. I am having some issues understanding how Spring forms work and are validated. My understanding thus far is that when you are using the your form is backed by a bean, meaning you must provide a bean to the JSP. You can also use the stand HTML forms but then you have to manually retrieve the request parameters in the controller.
Here is the issue I am having. I have a User bean that is using Hibernate Validator, and I have add, edit pages for users. The issue is I don't want the password field to appear on the Edit page, the password is going to be garbage anyway because its using BCrypt. However when the form is submitted validation fails because it expects the password to be present. There doesn't seem to be anyway to do partial bean implementation using Spring Form.
I would like to use Spring Form if possible because it reduces repetitive validation code, and its always nice to work with objects. My thoughts now are do I create an intermediate object and then translate the data from that to my bean. Seems tedious and can lead to the creation of way to many objects. My other thought is to just using plain old HTML forms and pull the params myself and set the values in the object.
I'm not sure what is the best approach or if I'm even thinking on the right track. Spring Forms and the validation is offers seems great, but seems like it isn't particularly flexible. Like I said I'm new to Spring so I may just be missing something or not understanding.
Another issue I have been wrestling with is having multiple objects needed on a form. Lets say I have a User bean, which has the following Properties.
private Role role;
private Country country;
So I need to pass User, List, and List to my JSP. I can get them to display fine, however if the form validation fails when it returns to that page, I lose my role and country objects, unless I re-add them to the model before returning the view name. Am I missing something here or is that the norm. It's a request object so I guess that makes sense but seems tedious to have to re-add them every time.
My understanding thus far is that when you are using the your form is
backed by a bean, meaning you must provide a bean to the JSP.
I'd say mostly true. The form is backed by a bean, but the Spring JSTL tags know how to get to the bean based on the set modelAttribute. The bean is living in what you would consider "page" scope, unless you add set your model attribute to be in session. Either way, if you are using the Spring JSTL tags, they are going to one or the other place to get it.
You can also use the stand HTML forms but then you have to manually
retrieve the request parameters in the controller.
Not true. You can "simulate" the same thing that the Spring JSTL tags are doing. Understand that JSTL tags are very much like macros. They are simply copying in some pre-determined block of code into the output with some very rudimentary conditional statements. The key bit that Spring MVC needs to wire the Model Attribute on the Controller side is the name and value, which are easy to decipher how those get generated/wired together.
However when the form is submitted validation fails because it expects
the password to be present.
You could create a "DTO" or "Data Transmission Object", which is basically a go-between to take the values from the UI and are converted in the Controller/Service layer to the real Model objects on the backend. Or, if you are lazy like me, put the User in session scope, in which case you don't have to post the value as Spring will take the one out of session and just updated the one or two fields you did post. Don't post the password, Spring wont set the password.
My thoughts now are do I create an intermediate object and then
translate the data from that to my bean.
Yes, this is the DTO I referred to. You only need to do it where you need to.
I'm not sure what is the best approach or if I'm even thinking on the
right track.
There are probably thousands of ways to do anything in coding, some more right or wrong than others. I know some developers who are design-Nazi's and would say you should always do it one way or another, but I am not one of those people. I think as long as you are consistent, and you are not doing something completely boneheaded you are on the right track. My #1 concern with all the code I write is maintainability. I
Don't want to spend 20hrs trying to re-learn what I did 6mo ago, so I tend to choose the simpler option
Hate repeating code, so I tend to choose more module designs
Hate having to spend 20hrs trying to re-learn what I did 6mo ago, so tend to make heavy use of JavaDoc and comments where I find the code is tricky (lots of loops, doing something weird, etc)
Another issue I have been wrestling with is having multiple objects
needed on a form.
There are several ways to deal with this too. I have never used it, but you CAN actually have more than one Model Attribute associated with the same form and Controller handler. I think you use a <spring:bind> tag or something. I have seen samples around, so Google it if you think you need that.
My approach is usually to either put something in session or build a DTO to hold all the things I need. The first I use more for things like lists to drive building the view, for instance if I have a drop down of States coming from a table. I would have a List of the States put into session and just use them from there, that way I only go after them once and done.
I use the DTO approach (some might call it a Form Bean) when I have a complex gaggle of things I need to change all at once, but the things are not necessarily connected directly. Just to point out: You can have nested objects in your model attributes and use them in your Spring JSTL tags. You can also have Collections (List, Set, Map) in your Model Attribute and get to those as well, although Spring doesn't handle nested Collections very well.
Hope that helps.

Attribute Routing vs Convention

Playing around with the Web.API 2.0 stuff- in particular Attribute Routing. The docs state that you can have attribute routing AND the 1.0 routing by convention... but these two don't seem to play that well together. For example, given these two methods:
public override HttpResponseMessage PutModel(SampleForm form)
[HttpPut("approvesampleform/{form}")]
public string ApproveSampleForm([FromBody]SampleForm form)
While I can call http://localhost/api/sampleform/approvesampleform just fine, a PUT to http://localhost/api/sampleform/ generates a Multiple actions were found that match the request error.
Is there any way that if a method is marked with the attribute routing it is ignored by the convention? This would be ideal... but I don't see any way to accomplish this in the docs.
Note: I don't see a asp.net-web-api-2 tag. Perhaps someone with more than 1500 rep can create it?
Right, RC (Release Candidate) did not have the logic where conventional routes cannot access attributed controller/actions. This change came post-RC. The scenario you are trying would work fine in post-RC bits.
Probably the docs you mentioned aren't very clear, but I think they mean that you could have attributed and convention based controllers work side-by-side and not particularly about mixing both attributed and conventional semantics in the same controller.
For time being you could probably use only attribute routing for your controller mentioned above.

Is there a preferred way to resolve CA1062 for MVC controller actions?

Running code analysis on the following action results in a CA1062 warning, advising I validate the parameter before using it:
[HttpPost]
public ActionResult Index(SomeViewModel vm)
{
if (!ModelState.IsValid)
return View(vm);
// ... other code
return View(vm);
}
I realize I could resolve the warning by adding:
if(vm==null)
throw new ArgumentNullException("vm");
I was under the impression that if default model binding succeeded the incoming parameter could never be null and would not need to be validated beyond "ModelState.IsValid".
Is that the case?
Is there a widely accepted technique for addressing this warning for MVC actions?
It is a public method, so you shouldn't be making assumptions about who will be calling it. While one caller (the MVC framework) might only invoke the method with non-null values, other potential callers might not be quite so "polite".
That said, if your code does not have other potential callers (which wouldn't be unusual for an MVC application, as opposed to a library), allowing a NullReferenceException to be thrown instead of an ArgumentNullException might be perfectly acceptable. That would depend largely on your expectations for future use and maintainability of the code base. (Amongst other things, a future maintenance developer would probably find it easier to identify a problem if it's signalled via an ArgumentNullException.)
I think that the model parameter can be null during development when MVC is not able to do the mapping, but I suppose that it shouldn't during normal operation.
In my opinion it is not bad to check your parameter as the warning points out.

MVC - How to mock / test POST (request.form) actions?

Has any one some example code of mocking request.form in a unit test, calling a controller and have the controller successfully bind the mock request.form to a view model using the Bind attribute or Controller.TryUpdateModel(model)?
This would appear to me to be a relatively common requirement, but alas a morning has gone and I am yet to find anything that's both adequate and working.
p.s. I've been chasing this all morning and have had no luck as the model binding is failing.
this always felt far harder than it needed to be. In the end the solution is simple and reasonably elegant although I'd prefer to see some conventional way to do this.
The trick is to add a FormCollection parameter to the Action:
this will be injected at run-time by MVC but allows mocking at test-time:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Search([Bind(Prefix = "")] ManageUsersViewModel manageUsersViewModel, FormCollection form)
{
in the test:
var form = new FormCollection
{
{"FindCriteria.SearchText", "searchText"},
{"FindCriteria.AccountIsPending", "true"},
{"FindCriteria.TermsHaveBeenAccepted", "true"}
};
sut.Search(new ManageUsersViewModel(), form);
Edit
Also it appears you will need two other things - Bind - does not work, you will need to make sure your controller has a controllercontext AND you will need to explicity call UpdateModel:
controller.ControllerContext = new ControllerContext();
...
UpdateModel(manageUsersViewModel, form.ToValueProvider());
MVC 3 and I'm having to revert to this to test a simple form submission. INSANE IN THE MEMBRANE

Can I use MVC validation attributes within a custom model binder?

I have lots of MVC validation attributes on my model. Everything works great when the defaultModelBinder binds my model on submit. But, I need to create a custom modelbinder. I'd like to continue using my validation attributes. Can I? If so, how?
I'm not sure whether this is possible or not, but one thing I can say is that if it is possible then the extension points for default model binder don't make it very discoverable. I spent several hours one day trying to get this to work to no avail.
In lieu of getting this to work, you can use the Controller's TryValidateModel() methods.

Resources