Does anyone know how to get the current RequestContext from the Application_Error event in global.asax?? My problem is that i need to do a redirect, and thereby need to have the url generated using UrlHelper - which takes the aformentioned RequestContext.
While there is no direct way of accessing the RequestContext, you can create one yourself:
RequestContext context = new RequestContext(new HttpContextWrapper(HttpContext.Current), RouteTable.Routes.GetRouteData(new HttpContextWrapper(HttpContext.Current)))
So the UrlHelper can be constructed via:
UrlHelper helper = new UrlHelper(new RequestContext(new HttpContextWrapper(HttpContext.Current), RouteTable.Routes.GetRouteData(new HttpContextWrapper(HttpContext.Current))));
Not pretty, but it gets the job done.
You can access the request context using
HttpContext.Current.Request.RequestContext
Or, if you're in the Global.asax you can use
Context.Request.RequestContext
directly.
Create an HttpContextBase from the Current HttpContext, and from that you can generate a UrlHelper:
// Create Http Context Base from current Context
var contextBase = new System.Web.HttpContextWrapper(System.Web.HttpContext.Current);
// Get its request context
System.Web.Routing.RequestContext requestContext = contextBase.Request.RequestContext;
// Build url helper from request context
var urlHelper = new System.Web.Mvc.UrlHelper(requestContext);
Related
In regular class, I need to read following from the HttpContext:
Controller and action name
Action's attribute (I could get that through HttpActionContext.ActionDescriptor.GetCustomAttributes<type>() but here I don't have HttpActionContext - I only have HttpContext)
Read argument (like actionContext.ActionArguments["paramName"], but again - I only have a HttpContext)
It's not an action filter and not a controller class. But, I can access HttpContext.
From asp.net core 3.0 https://stackoverflow.com/a/60602828/10612695
public async Task Invoke(HttpContext context)
{
// Get the enpoint which is executing (asp.net core 3.0 only)
var executingEnpoint = context.GetEndpoint();
// Get attributes on the executing action method and it's defining controller class
var attributes = executingEnpoint.Metadata.OfType<MyCustomAttribute>();
await next(context);
// Get the enpoint which was executed (asp.net core 2.2 possible after call to await next(context))
var executingEnpoint2 = context.GetEndpoint();
// Get attributes on the executing action method and it's defining controller class
var attributes2 = executingEnpoint.Metadata.OfType<MyCustomAttribute>();
}
I want to do an integration test for the below action.
How can I pass my requestDto object in the integration test?
Neither the GetAsync nor SendAsync method has an overload parameter to pass a custom object to the server.
[Route("{startDate:datetime}")]
[HttpGet]
public HttpResponseMessage Get(DateTime startDate, [FromBody]LessonplannerGetRequest request)
{
request.StartDate = startDate;
var lessonplannerResponse = _service.GetPeriodsByWeekStartDate(request);
return Request.CreateResponse<LessonplannerResponse>(HttpStatusCode.OK, lessonplannerResponse);
}
[Test]
public void Get_Lessons_By_Date()
{
// Arrange
var request = new HttpRequestMessage(HttpMethod.Get, _server.BaseAddress + "/api/lessonplanner/2014-01-14");
var myRequestDto = new LessonplannerGetRequest();
// Act => QUESTION: HOW do I pass the myRequestDto ???
var response = _client.SendAsync(request, new CancellationToken()).Result;
// Assert
Assert.That(response.StatusCode == HttpStatusCode.OK);
}
UPDATE
As Darrel Miller said:"Technically HTTP says you can send a body, it just says the body doesn't mean anything and cannot be used. HttpClient won't let you send one."
I post here my integration test with HttpClient doing a Get request with complex type + FromBody:
// Arrange
var request = new HttpRequestMessage(HttpMethod.Get, _server.BaseAddress + "/api/lessonplanner/2014-01-14");
var myRequestDto = new LessonplannerGetRequest{ FirstDayOfWeek = DayOfWeek.Sunday, SchoolyearId = 1, StartDate = DateTime.Today};
request.Content = new ObjectContent<LessonplannerGetRequest>(myRequestDto, new JsonMediaTypeFormatter());
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Act
var response = _client.SendAsync(request, new CancellationToken()).Result;
// Assert
Assert.That(response.StatusCode == HttpStatusCode.OK);
Of course is this is not the Http way some might consider doing it differentlly sending complex type via FromUri/query string.
HTML specifications says you cannot send a GET with a body.
HTTP specs allows it.
WebAPI allows it, because it is a service/REST and implements HTTP but not HTML, but many clients and browser won't allow it because they implement both specs and try to be strict.
As for the specifications (RFC1866, page 46; HTML 4.x section 17.13.3) itself, it states:
If the method is "get" and the action is an HTTP URI, the user agent takes the value of action, appends a `?' to it, then appends the form data set, encoded using the "application/x-www-form-urlencoded" content type.
(e.g. if you do a <form> with GET, it will parse all the form params and set them in the query string ?a=b).
In term of pure HTTP and in the context of REST services, nothing prevents that behavior, but not all clients will be able to handle it. It's mostly a best-practice advise when it comes to REST/WebAPI to not handle body data from HttpGet, only URI data (the opposite, POST /action?filter=all is usually tolerated for metadata/action qualifiers, but that's another discussion).
So yeah, it's at your own risk, even if used only internally. As not all clients handle it (e.g. HttpRequestMessage), so you might run into trouble like you have.
You should NOT pass a GET body with HTTPClient.
I was trying to work with the http context (with the help of Httpcontext.current) in the application_start event in global.asax then you will receive an Error:- HttpContext.Current Request is not available in this context.
The problem can easily be worked with a workaround by using a static constructor, which is fired when the object is accessed first. We can keep a flag in the Application_Beginrequest event and easily determine the request that initialized the application.
But in this case it gets created at every request, which is not required for me. I want to create or access Httpcontext.current once
My Code Is as Follows :-
`//var context = new HttpContextWrapper(HttpContext.Current);
//var routeData = RouteTable.Routes.GetRouteData(context) ?? new RouteData();
//var requestContext = new RequestContext(context, routeData);
//var urlHelper = new UrlHelper(requestContext);
//var url = urlHelper.Action("Home", "Index");
var httpContext = new HttpContextWrapper(HttpContext.Current);
UrlHelper urlHelper = new UrlHelper(new RequestContext(httpContext, new RouteData()));
if (urlHelper.RequestContext.HttpContext.Request.IsLocal)
{
}
//if (((requestContext.HttpContext).Request).IsLocal)
//{
//}`
There is no HttpContext nor HttpRequest instance in App_Start in integrated mode. You must work around this. If you really need to do something on first request, then register new BeginRequest handler in your global.asax and then unregister it when you are done.
I am trying for custom error handling at global level in Application_Error.
Exception ex = Server.GetLastError();
Server.ClearError();
AssortmentDefinitionLogManager.LogException(ex);
Context.RewritePath("/Error/Error");
IHttpHandler httpHandler = new MvcHttpHandler();
httpHandler.ProcessRequest(Context);
But i get this error
Error Message - The view '~/Views/Shared/Error' or its master was not found or no view engine supports the searched locations.
I have also tried this
var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
var redirectUrl = urlHelper.Action("Error", "Error");
Response.Redirect(redirectUrl);
create a controller called ErrorController and inside this controller create an action method called Error which returns an ActionResult (or ViewResult).
Then create a view under ~/Views/Error/ called error.cshtml.
This will solve your problem.
I need a HtmlHelper instance in my controller.
How can I instantiate one? thanks
This does not build:
var h = new HtmlHelper(new ViewContext(ControllerContext, new WebFormView("omg"), new ViewDataDictionary(), new TempDataDictionary()), new ViewPage());
Here is a screenshot of the error
Also, when I look at the list of methods under var h, I only see my custom extension methods and no regular ones like ActionLink. So that one needs to list as well. (solved by sternr)
Solution:
Ensure System.Web.Mvc.Html is included.
Here is the code to instantiate a HtmlHelper.
System.IO.TextWriter writer = new System.IO.StringWriter();
var html = new HtmlHelper(new ViewContext(ControllerContext, new WebFormView(ControllerContext, "omg"), new ViewDataDictionary(), new TempDataDictionary(), writer), new ViewPage());
HtmlHelper.ActionLink and most of the methods you'r probably looking for are extension methods declared under the System.Web.Mvc.Html namespace.
As for instantiating\using HtmlHelper inside your controller - this is a bad practice as your clearly combine UI code with Controller code. What are you trying to acheive?