I'm using ASP.NET MVC + C# and I have two controller action as follows:
public ActionResult Edit(Guid? id)
{
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(SomeModel model)
{
}
Now, in the browser I can navigate to the [GET] /controller/edit with no id and get an null argument exception (as expected), but what I'd like to know is how do I replicate this scenario in a unit test?
I have a GET and a POST version of the edit method so I can't feed controller.Edit(null) to test it as the code won't compile.
Thanks in advance!
One option would be to use the ActionName attribute to keep the URL the same, but have different method names.
[HttpGet]
[ActionName("Edit")]
public ActionResult GetEditForm(Guid? id)
{
...
}
[HttpPost]
[ActionName("Edit")]
public ActionResult SaveEditForm(SomeModel model)
{
...
}
Then you could of course call the right method from your unit test, and the routing bits of ASP.NET take care of getting the right method called.
Related
I want to pass object as parameter in my web api GET and POST method. My code is,
[HttpGet]
[Route("mytest/list/{model}")]
public IHttpActionResult GetAllTypes(TestModel model)
{
//my logic here
}
When I call this, console get an error its not found. I tried this,
[HttpGet]
[Route("mytest/list/{model?}")]
public IHttpActionResult GetAllTypes(TestModel model)
{
//my logic here
}
But, the parameter object gets null value.
Don't pass an object via GET.
POST an object and use [HttpPost] attribute.
If you're really want to do it via GET , you can use this :
[HttpGet]
public IHttpActionResult GetAllTypes([FromUri] TestModel model)
I have an action method in a controller that I'm calling via Ajax. The specification is:
[HttpPost]
public ActionResult SomeFunction(FormCollection form)
This works fine without any special routing configuration.
However, if I try to use a model as the parameter instead of the FormCollection, thus:
[HttpPost]
public ActionResult SomeFunction(SomeModel model)
I get a 500 error because the function can't be found.
What do I need to put in the RouteConfig to get this to work?
I would recommend using Help plugin: http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/creating-api-help-pages
When using POST I would specify signature as such:
#region POST
[Route("")]
public IHttpActionResult Post([FromBody]Contact newContact)
I have two actions, one for HttpGet with this signature:
[Route("NewsLetter/SelectEmail/{page?}")]
[HttpGet]
public ActionResult SelectEmail(int? page, string priCat, string secCat)
{
...
}
And one for HttpPost with this signature:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SelectEmail(int id)
{
...
}
After setting the aforementioned route for HttpGet method, I've noticed that the other method with HttpPost has stopped working, after digging around I've realized that the route for HttpGet also set itself for HttpPost, and it didn't work until I explicitly set a routing attribute for it:
[Route("NewsLetter/SelectEmail/{id}")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SelectEmail(int id)
{
...
}
I wanted to know, is it a bug?, if it's not, is there anyway to set a routing attribute for a [HttpGet] without also effecting the corresponding [HttpPost]?
You can't using POST and GET at the same time, because your Action will accept requests with any HTTP methods.
Try use AcceptVerbsAttribute to restrict HTTP methods in your RouteTable.
https://msdn.microsoft.com/en-us/library/system.web.mvc.acceptverbsattribute(v=vs.118).aspx
I have two action methods :
public ActionResult Edit(int id)
{
}
public ActionResult Edit(Modelname model, string[] strParam)
{
}
And I am calling the Edit(Modelname,string[]) from the unit test.
var actionResult = controller.Edit(model, strParam);
The code compiles at runtime , but when i debug the test method it gives me a method not found "MissingMethodException" . I tried commenting the Edit(int id) method and then debugging, still the same thing. Other tests are running fine, any help appreciated.
You have an ambiguous match for action methods in your controller. While it will compile just fine, ASP.NET MVC can't decide which method to use at runtime and it throws an exception. You need to make sure they respond to different type of HTTP requests or rename one of them.
I can't be sure with the info you provided but if the second method is processing a POST request, using HttpPost filter will solve the problem:
public ActionResult Edit(int id)
{
}
[HttpPost]
public ActionResult Edit(Modelname model, string[] strParam)
{
}
If that's not the case, renaming is the other solution. If you have a good reason not to do that, ASP.NET MVC provides ActionName filter to override the method name for ASP.NET MVC pipeline:
public ActionResult Edit(int id)
{
}
[ActionName("EditModel")]
public ActionResult Edit(Modelname model, string[] strParam)
{
}
This will make http://example.org/controller/EditModel hit the second method.
Suppose I have a CategoriesController for managing some kind of categories list. It has these action methods:
public ActionResult Get(Int32 categoryId);
public ActionResult Edit(Int32 categoryId);
[HttpPost]
public ActionResult Edit(Int32 categoryId, CategoryModel model);
public ActionResult Delete(Int32 categoryId);
[HttpPost]
public ActionResult Delete(Int32 categoryId, DeleteModel model);
All of these methods run the same code that verifies that categoryId is valid and the category exists, it retrieves it from the database, and performs access-level verification. Parts of the verification code returns an ActionResult directly, others do not (for example, if the categoryId doesn't exist, then it will return a Http404 action result immediately, but if everything's okay then it goes down to the action-specific code.
Is the best way to cut down on code duplication to do something like this?
private ActionResult EnsureCategory(Int32 categoryId, out DBCategory dbCategory);
public ActionResult Edit(Int32 categoryId) {
DBCategory dbCategory;
ActionResult error = EnsureCategory(categoryId, out dbCategory);
if( error != null ) return error;
// this now means that only 3 lines of code will be shared between the Action methods, but it still seems too much.
}
It's a shame C# doesn't support preprocessor macros, or something like it, because this would be a good place to use them. Unless there's a better approach?
Use action filters, do your validation inside OnActionExecuting method.
I ended up continuing to use the approach I suggested to myself in my original question. I did consider using #SteveB's T4 template suggestion, but I find T4 templates a bit hard to use.