I'd like to modify the default BAD_REQUEST_BODY template to return validation errors:
{
"message":$context.error.messageString,
"validationErrors":"$context.error.validationErrorString"
}
Is there a way to do this now?
Related
I have an ASP.NET Web API I wrote and have published. Now that its out there we are looking at doing some improvements, and these improvements involve changes to certain calls which means we need to version to keep existing clients working.
I have used attribute routing so far in my app. Methods are invoked by: Controller/Action via RoutePrefix and Route attributes.
When I do need to create a V2 of my classes, I only want to recreate the classes that have actually changed, and redirect other routes back to v1 classes because they haven't changed. (Otherwise I just end up with a lot of boilerplate code, or duplicate code).
What I want to do is have the following routes work for my v1 version of classes:
Controller/Action
For V2 I want any new classes to go to V2, and any classes that haven't changed I want to return the HttpControllerDescriptor from V1 class. The route would look like v2/Controller/Action but would be redirected to Controller/Action.
I've implemented a IHttpControllerSelector and return the appropriate HttpControllerDescriptors but its not making the call into the method. I believe its because the routing information doesn't match the action. (When I put in an IHttpActionSelector and trace the exception it says "multiple actions were found that match the request).
So, I'm guess I'm wondering: Is this even possible? Is this the best way to achieve what I'm trying to do?
Here is what I implemented for versioning support in asp.net web api. Important to note I did not use attribute routing but explicit routes in WebApiConfig.cs so if you want to follow this pattern you would need to switch back to explicit routes. Also I do not prefer version information in the actual route, I use a custom (ie. "version") parameter in Accept header. I also set the version per mime type as in the below example. If version number is not set by the client or if the requested version does not exist this will fall back to default controller.
Create a class and inherit from DefaultHttpControllerSelector so you can fallback to base class behavior when you wanted to.
Override SelectController method as such:
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
IDictionary controllers = GetControllerMapping();
IHttpRouteData routeData = request.GetRouteData();
string controllerName = (string)routeData.Values["controller"];
HttpControllerDescriptor controllerDescriptor;
if (string.IsNullOrWhiteSpace(controllerName))
{
return base.SelectController(request);
}
if (!controllers.TryGetValue(controllerName, out controllerDescriptor))
{
return null;
}
string version = GetVersionFromAcceptHeader(request);
if (string.Equals(version, "1"))
{
return controllerDescriptor;
}
string newName = string.Concat(controllerName, "V", version);
HttpControllerDescriptor versionedControllerDescriptor;
if (controllers.TryGetValue(newName, out versionedControllerDescriptor))
{
return versionedControllerDescriptor;
}
return controllerDescriptor;
}
Register this controller selector in your webapiconfig Register method:
config.Services.Replace(typeof(IHttpControllerSelector), new YourControllerSelector(config));
While reading Facebook Analytic's documentation, I stumbled upon this default event called EVENT_NAME_VIEWED_CONTENT that accepts 3 params: CONTENT_TYPE, CONTENT_ID and CURRENCY.
I'm wondering if Facebook provide a way match the CONTENT_ID and CONTENT_TYPE to get the resource's name maybe through a standardized endpoint that my backend should be implementing or something.
Disclaimer: I know I could just make a custom event that would also receive the name or title parameter, but I'm interested in using the defaults for now.
There's currently no way to configure Facebook Analytics to do this lookup through your own backend. However, you can use custom parameters with predefined events:
FB.AppEvents.logEvent(
FB.AppEvents.EventNames.VIEWED_CONTENT,
null /* valueToSum */,
{
[FB.AppEvents.ParameterNames.CONTENT_ID]: contentId,
name: contentName,
},
);
There's also nothing stopping you from passing a string to CONTENT_ID if you're really only interested in the resource's name.
FB.AppEvents.logEvent(
FB.AppEvents.EventNames.VIEWED_CONTENT,
null /* valueToSum */,
{
[FB.AppEvents.ParameterNames.CONTENT_ID]: contentName,
},
);
I have http requests such as the one below being sent to an nginx server:
GET /app/handler?id=1234¶m1=cbd¶m2=234
Now, I want to rewrite the request to a different handler depending on the id param in the request. eg. redirect to handler_even for even ids and handler_odd for odd ids. This is shown below:
GET /app/handler?id=1234¶m1=cbd¶m2=234 => /app/handler_even?id=1234¶m1=cbd¶m2=234
GET /app/handler?id=123¶m1=cbd¶m2=234 => /app/handler_odd?id=123¶m1=cbd¶m2=234
I can do the rewrite using proxy_pass, but I'm unsure how to redirect using the id parameter value. Any idea how I could go about this? Would using "if" be the best way to go about this?
Any pointers would be useful
Rather than use an if directive, you could use a map. To internally rewrite the URI use:
map $arg_id $handler {
default /app/handler_even;
~[13579]$ /app/handler_odd;
}
server {
...
location = /app/handler {
rewrite ^ $handler last;
}
...
}
The map should be located at the same level as your server directive (as shown above), i.e. within the http container.
See this document for details.
I'm upgrading a custom solution where I can dynamically register and unregister Web Api controllers to use the new attribute routing mechanism. However, it seems to recent update to RTM break my solution.
My solution exposes a couple of Web Api controllers for administration purposes. These are registered using the new HttpConfigurationExtensions.MapHttpAttributeRoutes method call.
The solution also allows Web Api controllers to be hosted in third-party assemblies and registered dynamically. At this stage, calling HttpConfigurationExtensions.MapHttAttributeRoutes a second time once the third-party controller is loaded would raise an exception. Therefore, my solution uses reflection to inspect the RoutePrefix and Route attributes and register corresponding routes on the HttpConfiguration object.
Unfortunately, calling the Web Api results in the following error:
"No HTTP resource was found that matches the request URI".
Here is a simple controller that I want to use:
[RoutePrefix("api/ze")]
public sealed class ZeController : ApiController
{
[HttpGet]
[Route("one")]
public string GetOne()
{
return "One";
}
[HttpGet]
[Route("two")]
public string GetTwo()
{
return "Two";
}
[HttpPost]
[Route("one")]
public string SetOne(string value)
{
return String.Empty;
}
}
Here is the first solution I tried:
configuration.Routes.MapHttpRoute("ZeApi", "api/ze/{action}");
Here is the second solution I tried:
var type = typeof(ZeController);
var routeMembers = type.GetMethods().Where(m => m.IsPublic);
foreach (MethodInfo method in routeMembers)
{
var routeAttribute = method.GetCustomAttributes(false).OfType<RouteAttribute>().FirstOrDefault();
if (routeAttribute != null)
{
string controllerName = type.Name.Substring(0, type.Name.LastIndexOf("Controller"));
string routeTemplate = string.Join("/", "api/Ze", routeAttribute.Template);
configuration.Routes.MapHttpRoute(method.Name, routeTemplate);
}
}
I also have tried a third solution, whereby I create custom classes that implement IHttpRoute and trying to register them with the configuration to no avail.
Is it possible to use legacy-style route mapping based upon the information contained in the new routing attributes ?
Update
I have installed my controller in a Web Application in order to troubleshoot the routing selection process with the Web Api Route Debugger. Here is the result of the screenshot:
As you can see, the correct action seems to be selected, but I still get a 404 error.
Update2
After further analysis, and per Kiran Challa's comment below, it seems that the design of Web Api prevents mixing attribute routing and conventional routing, and that what I want to do is not possible using this approach.
I have created a custom attribute [RouteEx] that serves the same purpose of the Web Api [Route] attribute, and now my code works perfectly.
I guess, since this is not possible using the conventional attribute routing, none of the answers on this question could legitimately be consisered valid. So I'm not nominating an answer just yet.
You shouldn't be required to use reflection and inspect the attribute-routing based attributes yourself. Attribute routing uses existing Web API features to get list of controllers to scan through.
Question: Before the switch to attribute routing, how were you loading these assemblies having the
controllers?
If you were doing this by IAssembliesResolver service, then this solution should work even with attribute routing and you should not be needing to do anything extra.
Regarding your Update: are you calling MapHttpAttributeRoutes?
I have some custom validation that I need to perform that involves checking the selected option of a dropdown and flagging it as invalid should the user select a specific option.
I am using ASP.NET MVC 2 and have a custom Validator and custom server side and client side validation rules as described in this blog article. The server side validation is working fine, however, the client side validation is failing.
Here is the javascript validation rule:
Sys.Mvc.ValidatorRegistry.validators["badValue"] = function(rule) {
var badValue = rule.ValidationParameters["badValue"];
return function(value, context) {
if (value != badValue) {
return true;
}
return rule.ErrorMessage;
};
};
The rule is being applied to the dropdowns successfully, and placing a breakpoint within the returned function confirms that the validation is firing, and that the 'badValue' is being correctly set. However, 'value' is always null, and so the check always fails. What am I doing wrong?