I'm using MVC3 and want to create a route to an ashx file. I've created an Generic Handler with this code in:
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var handler = new TileHandler();
handler.ProcessRequest(requestContext);
return handler;
}
I've set a route up in the Global.asax which works fine. However my TileHandler which is an ashx page expects a HttpContext to be passed to it not a RequestContext. I can overload the method, but it obviously still wants the standard method invoked on call.
My question is therefore how can you use an ashx page passing in a RequestContext object?
Thanks in advance.
Change your TileHandler to inherit from System.Web.Mvc.MvcHandler instead.
Example.
Related
I am using Liferay 6.2. I made a hook to add some extra fields in User-My Acccount page. On key press of these fields, an ajax call needs to be invoked. I read lifery service override and trying to follow the same approach: It works for updating user with new fields.
However, for ajax call, i need to override serve resource method somewhere. But i am not sure where exactly to call serve resource().
My approach is as follows:
In details.jsp
<portlet:resourceURL var ="userProfileURL"></portlet:resourceURL>
In js:
I call the ajax by using AUI io request: I pass mode as a parameter to check if it goes inside serveResource or not..
But before going to serve resource, it gives me an error saying userProfileURL is not defined. I have also included needed imports for it in jsp.
In userServiceImpl class that extends UserServiceWrapper, i tried to override serveResource:
public void serveResource(ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws PortletException {
String mode = ParamUtil.getString(resourceRequest,"mode")
if(mode.equals("getData")
{
// do needed processings & return data
}
else {
// super.serveResource(resourceRequest, resourceResponse);
}
But i get an error that says:
The method serveResource(ResourceRequest, ResourceResponse) is undefined for the type UserServiceWrapper
Is there any way to make ajax calls in hooks for user account page or am i oveririding on the wrong place?
I'm very new to MVC. How do I perform a Response.Clear() from within an MVC3 aspx page?
I have tried:
Response.Clear();
ViewContext.HttpContext.Response.Clear();
Neither of them seem to function at all, in that any HTML content before the statements remain in the output. The only thing that seems to work is Response.Close(), but of course that doesn't allow me to output anything afterwards.
The reason for wanting this simply a testing/debugging exercise - I just want to be able to clear the buffered output, from inline code in the aspx page, and output something else afterwards. Similar to what one could do with web forms.
Note, I don't want to perform this within the controller, as it means re-compiling every time I make a change, as well as losing session state. The point of this is to fiddle within the aspx page to avoid re-compiling each time.
Taken from your comment, that you want to mess with your code before an Action is executed and afterwards, the most ideal solution is to use custom ActionFilters:
public interface IActionFilter
{
void OnActionExecuting(ActionExecutingContext filterContext);
void OnActionExecuted(ActionExecutedContext filterContext);
}
OnActionExecuting is used to execute code before your Controller action is called, while OnActionExecuted is used after the action method has done its job.
So you hook up a custom filter like this:
public class MyCustomFilter : IActionFilter
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//put your custom response and shenanigans here
...
return;
}
}
After this you can decorate your controller method with this filter:
[MyCustomFilter]
public ActionResult ListSomething()
{
/* magic happens here */
}
There's a lot you can achieve here, but I suggest some further reading into this:
http://www.dotnet-tricks.com/Tutorial/mvc/b11a280114-Understanding-ASP.NET-MVC-Filters-and-Attributes.html
http://msdn.microsoft.com/en-us/magazine/gg232768.aspx
http://www.asp.net/mvc/tutorials/older-versions/controllers-and-routing/understanding-action-filters-cs
http://msdn.microsoft.com/en-us/library/gg416513(vs.98).aspx
Sidenote: If this is just for learning and debugging purposes, I'd take a look at newer mvc versions (4, 5).
In stead of focussing on Response, perhaps you should focus on what you wish to return in your controller method.
If you wish to return a full rendered View
return View("myView");
If you wish to return a PartialView
return PartialView("myPartialView");
If you wish to return a FileStream
return File(myBytes, "filename.ext");
If you wish to return a Json string,
return Json(myObject);
Try
ViewContext.HttpContext.Response.Flush();
Istead of :
ViewContext.HttpContext.Response.Clear();
I've created a custom HandleErrorAttribute in order to implement logging as part of the exception handling. However, unrelated to the logging, I have run into an issue where I need to render a partialview on an Ajax request instead of a JsonResult. I can detect that it is an ajax request but I can't figure out how to determine when it is appropriate to generate a JsonResult or a PartialView. In most instances, a JsonResult is appropriate but in some cases a PartialView is appropriate. Is there a way to determine what the action is expecting from within OnException()?
I was hoping to find a way to detect the required type of response via a property in filterContext or something that would allow me to dynamically determine the expected response type. In all of my research, I could not find anything that would make that possible. So, I dealt with the situation by adding a bool property (defaulting to false) to the custom HandleErrorAttribute class. I then applied this attribute to the method that is responding with a partialView instead of a JsonResult, setting the property value to true. When the property value is true, the OnException() method responds with a partialView instead of a JsonResult.
If there is a better way, please let me know.
I think the following snippets could help you detect the required type of response
protected override void OnException(ExceptionContext filterContext)
{
//Determine the return type of the action
string actionName = filterContext.RouteData.Values["action"].ToString();
Type controllerType = filterContext.Controller.GetType();
var method = controllerType.GetMethod(actionName);
var returnType = method.ReturnType;
if (returnType.Equals(typeof(JsonResult)))
{
}
}
I know how to get the current controller name
HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString();
But is there any way to get the current controller instance in some class (not in an action and not in a view)?
By default you can only access the current Controller inside a controller with ControllerContext.Controller or inside a view with ViewContext.Context. To access it from some class you need to implement a custom ControllerFactory which stores the controller instance somewhere and retrieve it from there. E.g in the Request.Items:
public class MyControllerFactory : DefaultControllerFactory
{
public override IController CreateController(RequestContext requestContext, string controllerName)
{
var controller = base.CreateController(requestContext, controllerName);
HttpContext.Current.Items["controllerInstance"] = controller;
return controller;
}
}
Then you register it in your Application_Start:
ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());
And you can get the controller instance later:
public class SomeClass
{
public SomeClass()
{
var controller = (IController)HttpContext.Current.Items["controllerInstance"];
}
}
But I would find some another way to pass the controller instance to my class instead of this "hacky" workaround.
Someone will have to correct me if what I am doing is detrimental to the whole Asp.Net page life cycle / whatever but surely you can do this:
In controller
ViewBag.CurrentController = this;
In view
var c = ViewBag.CurrentController;
var m1 = BaseController.RenderViewToString(c, "~/Views/Test/_Partial.cshtml", null);
In my case, I had a base controller that all controllers extend. In that base controller lived a static method called RenderViewToString and it required a controller. Since I figured I could just instantiate a new instance of an empty controller at this point for c, I just sent it to the view in the lovely ViewBag container that exists in the world of Asp.Net MVC. For reasons I could not go into now, I could not retrieve the string in the controller and send just that back to the view (this was what I had done earlier before requirements changed).
The reason I have done it this way is in other languages like PHP and JS, there are similar simple ways to transfer classes around.
We have an a PHP application that we are converting to MVC. The goal is to have the application remain identical in terms of URLs and HTML (SEO and the like + PHP site is still being worked on). We have a booking process made of 3 views and in the current PHP site, all these view post back to the same URL, sending a hidden field to differentiate which page/step in the booking process is being sent back (data between pages is stored in state as the query is built up).
To replicate this in MVC, we could have a single action method that all 3 pages post to, with a single binder that only populates a portion of the model depending on which page it was posted from, and the controller looks at the model and decides what stage is next in the booking process. Or if this is possible (and this is my question), set up a route that can read the POST parameters and based on the values of the POST parameters, route to a differen action method.
As far as i understand there is no support for this in MVC routing as it stands (but i would love to be wrong on this), so where would i need to look at extending MVC in order to support this? (i think multiple action methods is cleaner somehow).
Your help would be much appreciated.
I have come upon two solutions, one devised by someone I work with and then another more elegant solution by me!
The first solution was to specify a class that extends MVcRouteHandler for the specified route. This route handler could examine the route in Form of the HttpContext, read the Form data and then update the RouteData in the RequestContext.
MapRoute(routes,
"Book",
"{locale}/book",
new { controller = "Reservation", action = "Index" }).RouteHandler = new ReservationRouteHandler();
The ReservationRouteHandler looks like this:
public class ReservationRouteHandler: MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var request = requestContext.HttpContext.Request;
// First attempt to match one of the posted tab types
var action = ReservationNavigationHandler.GetActionFromPostData(request);
requestContext.RouteData.Values["action"] = action.ActionName;
requestContext.RouteData.Values["viewStage"] = action.ViewStage;
return base.GetHttpHandler(requestContext);
}
The NavigationHandler actually does the job of looking in the form data but you get the idea.
This solution works, however, it feels a bit clunky and from looking at the controller class you would never know this was happening and wouldn't realise why en-gb/book would point to different methods, not to mention that this doesn't really feel that reusable.
A better solution is to have overloaded methods on the controller i.e. they are all called book in this case and then define your own custome ActionMethodSelectorAttribute. This is what the HttpPost Attribute derives from.
public class FormPostFilterAttribute : ActionMethodSelectorAttribute
{
private readonly string _elementId;
private readonly string _requiredValue;
public FormPostFilterAttribute(string elementId, string requiredValue)
{
_elementId = elementId;
_requiredValue = requiredValue;
}
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
if (string.IsNullOrEmpty(controllerContext.HttpContext.Request.Form[_elementId]))
{
return false;
}
if (controllerContext.HttpContext.Request.Form[_elementId] != _requiredValue)
{
return false;
}
return true;
}
}
MVC calls this class when it tries to resolve the correct action method on a controller given a URL. We then declare the action methods as follows:
public ActionResult Book(HotelSummaryPostData hotelSummary)
{
return View("CustomerDetails");
}
[FormFieldFilter("stepID", "1")]
public ActionResult Book(YourDetailsPostData yourDetails, RequestedViewPostData requestedView)
{
return View(requestedView.RequestedView);
}
[FormFieldFilter("stepID", "2")]
public ActionResult Book(RoomDetailsPostData roomDetails, RequestedViewPostData requestedView)
{
return View(requestedView.RequestedView);
}
[HttpGet]
public ActionResult Book()
{
return View();
}
We have to define the hidden field stepID on the different pages so that when the forms on these pages post back to the common URL the SelectorAttributes correctly determines which action method to invoke. I was suprised that it correctly selects an action method when an identically named method exists with not attribute set, but also glad.
I haven't looked into whether you can stack these method selectors, i imagine that you can though which would make this a pretty damn cool feature in MVC.
I hope this answer is of some use to somebody other than me. :)