Html.Action does not render actionmethods annotated with [HttpPost] - asp.net-mvc

I have the follwing method on my controller:
[HttpPost]
public ActionResult UnplannedCourses(int studentId)
{
var model = CreateUnplannedCourseModel(studentId);
return View("UnplannedCourses", model);
}
and in my view I try:
<div class="unplannedcourses">
#Html.Action("UnplannedCourses", "Student", new { studentId = Model.StudentId })
</div>
But that gives an error: A public action method 'UnplannedCourses' was not found on controller 'Digidos.MVCUI.Controllers.StudentController'.
If I leave the [HttpPost] out, then it works, but I use the action later again from javascript so I would like to have only POST available.
Any ides?

I think my best bet is a new attribute based on the MVC sources:
public class ChildishAttribute : ActionMethodSelectorAttribute
{
private static readonly AcceptVerbsAttribute _innerAttribute = new AcceptVerbsAttribute(HttpVerbs.Post);
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
var isPost = _innerAttribute.IsValidForRequest(controllerContext, methodInfo);
var isChildAction = controllerContext.IsChildAction;
var isAjax = controllerContext.RequestContext.HttpContext.Request.IsAjaxRequest();
return isChildAction || (isAjax && isPost);
}
}
[Childish]
public ActionResult UnplannedCourses(int studentId)
{
var model = CreateUnplannedCourseModel(studentId);
return View("UnplannedCourses", model);
}

Html.Action is a html helper method and invokes your controller action with Http GET not POST.
Html.Action is a html helper method and invokes your controller action which accepts GET requests.
Edit:
If your intention is to protect that page from viewing through your browser, implement ChildActionOnly attribute as follows:
[ChildActionOnly]
public ActionResult UnplannedCourses(int studentId)
{
var model = CreateUnplannedCourseModel(studentId);
return View("UnplannedCourses", model);
}
Edit:
If you would like to invoke your action through Http POST via JavaScript, have a look the at following post:
Working With JQuery Ajax API on ASP.NET MVC 3.0

Related

How to direct to POST action in ActionAsPDF?

I am creating an MVC 5 application. I am using Rotativa to generate PDFs
they have a method called
public ActionAsPdf(string action, object routeValues);
I am having trouble to direct to POST method of an action
this is that GET and POST actions
[HttpGet]
[ValidateInput(false)]
public ActionResult Create_Brochure(IEnumerable<ProductsPropertiesVM> model)
{
.............
return View(selectedIDs);
}
[HttpPost]
[ValidateInput(false)]
public ActionResult Create_Brochure(string m)
{
return View();
}
Once I run this program its directing to GET method but I want to direct to POST action
using following method
public ActionResult PrintIndex()
{
return new ActionAsPdf("Create_Brochure") { FileName = "Test.pdf" };
}
You need to match the parameters of the POST version of Create_Brochure:
return new ActionAsPdf("Create_Brochure", new List<ProductsPropertiesVM>())
{
FileName = "Test.pdf"
};
Of course, you'll have to pass the correct model data instead of the List<ProductsPropertiesVM>.

Can I give SEO-friendly URL Segment's to action on a PageController?

Is it possible to define the URL segment for an action on a PageController<T>?
Take for example the following controller,
public class MyPageController : PageController<MyPageData>
{
public ActionResult Index(MyPageData currentPage)
{
return View(currentPage);
}
[HttpPost]
public ActionResult SubmitForm(MyPageData currentPage, FormModel model)
{
// ...
return Redirect("/");
}
}
New, let's say we've created an instance of MyPageData at the URL /my-page, if we render a form who's action is the SubmitForm action, we'll get a URL like so <form action="/my-page/SubmitForm">
#using(Html.BeginForm("SubmitForm"))
{
...
}
My question is, is there any way to define or control how the URL segment for the non-Index action is rendered, so the form would render like so <form action="/my-page/submit-form">?
You should be able to use the standard ASP.NET action name attribute, such as
public class MyPageController : PageController<MyPageData>
{
[HttpPost]
[ActionName("submit-form")]
public ActionResult SubmitForm(MyPageData currentPage, FormModel model)
{
// ...
return Redirect("/");
}
}

Prevent partial view from loading

How can i prevent a partial view from being loaded by typing http://mydomain.com/site/edit/1 Is there any way of doing this?
/Martin
If you load your partials through Ajax then you can check if the request HTTP header HTTP_X_REQUESTED_WITH is present and its value is equals to XMLHttpRequest.
When a request is made through the browser that header is not present
Here is a very simple implementation of an Action Filter attribute that does the job for you
public class CheckAjaxRequestAttribute : ActionFilterAttribute
{
private const string AJAX_HEADER = "X-Requested-With";
public override void OnActionExecuting( ActionExecutingContext filterContext ) {
bool isAjaxRequest = filterContext.HttpContext.Request.Headers[AJAX_HEADER] != null;
if ( !isAjaxRequest ) {
filterContext.Result = new ViewResult { ViewName = "Unauthorized" };
}
}
}
You can use it to decorate any action where you want to check if the request is an ajax request
[HttpGet]
[CheckAjaxRequest]
public virtual ActionResult ListCustomers() {
}
I believe the [ChildActionOnly] attribute is what you're looking for.
[ChildActionOnly]
public ActionResult Edit( int? id )
{
var item = _service.GetItem(id ?? 0);
return PartialView( new EditModel(item) )
}
Phil Haack has an article using it here

Accessing ASP.NET MVC Action Parameters

This must be simple, but I can't seem to figure it out. I am setting an action parameter inside an action filter as follows:
public class MyFilter : ActionFilterAttribute
{
public override void OnActionExecuting (ActionExecutingContext filterContext)
{
filterContext.ActionParameters["MyParam"] = "MyValue";
}
}
I am applying the filter to an entire controller as follows:
[MyFilter]
public class HomeController : Controller
{
public ActionResult Index()
{
// How do I access MyParam here?
return View();
}
}
}
How do I access MyParam inside an action method?
Maybe you could use:
[MyFilter]
public ActionResult Index(string MyParam)
{
//Do something with MyParam
return View();
}
You can decorate whole controller with [MyFilter] or only one action.
I'm hoping this will work:
var myParam = ValueProvider.GetValue("MyParam").RawValue as string;
Since ValueProvider is what modelbinders use to get the values I would think it should be able to get the value set in your filter.

Routing to the actions with same names but different parameters

I have this set of routes:
routes.MapRoute(
"IssueType",
"issue/{type}",
new { controller = "Issue", action = "Index" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Here is the controller class:
public class IssueController : Controller
{
public ActionResult Index()
{
// todo: redirect to concrete type
return View();
}
public ActionResult Index(string type)
{
return View();
}
}
why, when i request http://host/issue i get The current request for action 'Index' on controller type 'IssueController' is ambiguous between the following action methods:
I expect that first one method should act when there is no parameters, and second one when some parameter specified.
where did i made mistake?
UPD: possible duplicate: Can you overload controller methods in ASP.NET MVC?
UPD 2: due to the link above - there is no any legal way to make action overloading, is it?
UPD 3: Action methods cannot be overloaded based on parameters (c) http://msdn.microsoft.com/en-us/library/system.web.mvc.controller%28VS.100%29.aspx
I would have one Index method that looks for a valid type variable
public class IssueController : Controller
{
public ActionResult Index(string type)
{
if(string.isNullOrEmpty(type)){
return View("viewWithOutType");}
else{
return View("viewWithType");}
}
}
EDIT:
How about creating a custom attribute that looks for a specific request value as in this post StackOverflow
[RequireRequestValue("someInt")]
public ActionResult MyMethod(int someInt) { /* ... */ }
[RequireRequestValue("someString")]
public ActionResult MyMethod(string someString) { /* ... */ }
public class RequireRequestValueAttribute : ActionMethodSelectorAttribute {
public RequireRequestValueAttribute(string valueName) {
ValueName = valueName;
}
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {
return (controllerContext.HttpContext.Request[ValueName] != null);
}
public string ValueName { get; private set; }
}
I ran into a similar situation where I wanted my "Index" action to handle the rendering if I had an ID specified or not. The solution I came upon was to make the ID parameter to the Index method optional.
For example, I originally tried having both:
public ViewResult Index()
{
//...
}
// AND
public ViewResult Index(int entryId)
{
//...
}
and I just combined them and changed it to:
public ViewResult Index(int entryId = 0)
{
//...
}
You can do it using an ActionFilterAttribute that checks the parameters using reflection (I tried it) but it's a bad idea. Each distinct action should have its own name.
Why not just call your two methods "Index" and "Single", say, and live with the limitation on naming?
Unlike methods that are bound at compile time based on matching signatures, a missing route value at the end is treated like a null.
If you want the [hack] ActionFilterAttribute that matches parameters let me know and I'll post a link to it, but like I said, it's a bad idea.
All you have to do is mark your second Action with [HttpPost]. For instance:
public class IssueController : Controller
{
public ActionResult Index()
{
// todo: redirect to concrete type
return View();
}
[HttpPost]
public ActionResult Index(string type)
{
return View();
}
}

Resources