Sitecore Web Api default context language - asp.net-web-api

My target is if the request is
http://myapi.com/da-DK/api/products/all
I would return the products from the DK language.
But if the request is
http://myapi.com/api/products/all
meaning no language is requested, it would return products from a default language. In this case "en".
This is what I have in the webapiconfig.
config.Routes.MapHttpRoute(
name: "mypi",
routeTemplate: "{language}/api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional, language = "en" }
);
The problem is if no language requested, it does not take english an default. Rather it takes the last requested language.
Can I somehow force sitecore to use default language if no language is requested?

I know you solved this using a resolver but I think those are 2 different routes..meaning you can create another route:
config.Routes.MapHttpRoute(
name: "mypinolang",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional, language = "en" }
);
Then, you can have your API method to accept "language" as a parameter. However, this answer may not work depending on your other API methods as it can get confusing.

Related

Visual Studio Web API: How to change the routing path

I am working on Web Api. By default, it uses the api/{controller}/{id} as a url. I am able to have it to route api/device/{controller}/{id} but this will affect to all Web API route to that path.
But I only want certain controller to be in api/device/{controller}/{id} and the rest will go to another path.
I saw something like RoutePrefix but it doesn't seem to work...
[RoutePrefix (api/data/abc)] where abc is the controller name.
Add the custom route mapping in WebApiConfig.cs file before default route map:
By adding this before, any requests which matches the custom route will be executed, else the other one.
config.Routes.MapHttpRoute(
name: "CustomRoute",
routeTemplate: "api/device/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
If you want to customize the routing with a per controller approach, then you have to use Attribute Routing instead of the standard convention-based routing.
Decorate your controllers with RoutePrefix attribute, and your actions with Route attribute in this way:
[RoutePrefix("api/device/mydevice")]
public class MyDeviceController : ApiController {
[Route("{id}")]
[HttpGet]
public IHttpActionResult Get(int id) {
//DoWork
//...
}
}
And remember to enable attribute routing on the HttpConfiguration object:
config.MapHttpAttributeRoutes();
You may also remove MapHttpRoute method calls if you do not want to allow access to your actions in the standard convention-based way.
More on attribute routing on the official documentation.

Adding custom method to WebAPI

I am new to the WebAPI and I got stuck in a problem. I am using API controller which contains two Get methods. One is used for GetAll while other retrieves data on the basis of ID. Now what I want to do is to implement another get method which takes string and returns records. I have made that method and call that it does not work as my route was default API route which was like:
config.Routes.MapHttpRoute(name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } );
When I added a new route to call my custom GetMethod:
config.Routes.MapHttpRoute(name: "Custom", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } );
I was able to call my custom GetMethod but now I lose the restful method with id parameters. How can I use both methods?
Have you tried using your second route only and call as
api/customer/get/1
api/customer/getall/
api/customer/getmethod/one
In the above, customer is the controller name. You have to replace with yours.
Please check whether you have the routes in the webapiconfig.cs file. Please refer this article for more help.
Better not to change routes.
You can use Action Name to differentiate the calls and can add more functions. Take a look at this answer:
How to add custom methods to ASP.NET WebAPI controller?

Actions and QueryString parameters in Web API

I want to have my generic route determine if a query string was passed in the Url like this
http://localhost/query/DailyLogs/1?dateOfLog='1/13/2013'
Here is my current Route definition:
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "query/{controller}/{id}",
defaults: new { id = RouteParameter.Optional}
);
I have read some answers that say to add the dateOfLog value as an optional action on the Route defintion:
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "query/{controller}/{id}/{dateOfLog}",
defaults: new { id = RouteParameter.Optional,
dateOfLog = RouteParameter.Optional }
);
This does not seem to work, maybe I am doing something wrong, I am not sure.
This is how I am currently handling the problem, but I would like to use the ModelBinding power of the Routing Engine:
var queryValue = Request.RequestUri.ParseQueryString();
string dateOfLog = queryValue["dateOfLog"];
Please tell me how to create a Route definition that will use ModelBinding correctly and map my custom url to the controller's parameters.
In the controller action, just include DateTime dateOfLog as a method parameter and continue to use the query string as it will get mapped just fine, Web API will use the correct method overload if it finds it.

Specify valid controllers for a route

I've to provide two Web API controllers PublicController and PrivateController for our system. These should have the following routes:
/public/{controller}/{id}
and
/private/{controller}/{id}
On the firewall, all requests to /private are blocked and only available from inside the network. But by convention, both of my controllers are available for both routes, so I could request PrivateController (which should only be available under /private) with the url /public/PrivateController/1.
Is there a way to specify valid controllers for a route, so that the PrivateController is only available for the private route? Or are there some other practices to fullfill this requirement?
Thanks for your replies.
You can use the constraints parameter to provide restrictions on the controller name in the simplest case with a very simple regular expression:
config.Routes.MapHttpRoute(
name: "private",
routeTemplate: "api/private/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { controller = #"private" }
);
config.Routes.MapHttpRoute(
name: "public",
routeTemplate: "api/public/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { controller = #"public" }
);
So the now the "private" route only accept the controller which named Private and the "public" route will only accept the controller which named Public. If you have multiple public and private controllers you can easily extend the regex to match them.
If the regex is not enough for your needs you can create your custom route contaraint with implementing the IRouteConstraint interface. You can find an example implantation In this article.

Web API route mapping to root

I am setting up an ASP.NET MVC 4 Web API to accept requests from a 3rd party server, and I simply can't figure out how to set the route mappings.
Assume the 3rd party server expects to get responses for:
http://[my_server]/authorize?user=[user name]&session=[session token]&item=[item]
http://[my_server]/release?user=[user name]&session=[session token]
Alternatively, the requests can use a dedicated path, i.e.:
http://[my_server]/***api***/authorize?user=[user name]&session=[session token]&item=[item]
http://[my_server]/***api***/release?user=[user name]&session=[session token]
I would like to be able to support both alternatives.
Additional requests, following the more traditional /controller/id form, should be implemented too, but I'd like to focus on the above (I'm not even sure that Web API is the way to go here).
I have written the following controller:
public class MyController : ApiController
{
[HttpGet]
[ActionName("authorize")]
public string Authorize(string user, string session, string item)
{
...
// return "OK" or "DENY";
}
[HttpGet]
[ActionName("release")]
public string Release(string user, string session)
{
...
return "OK";
}
}
and tried everything I could find in SO and elsewhere in WebAppConfig.Register, but I keep getting a 404 error when I try the request in the browser:
http://localhost:22332/api/authorize?user=ury&session=token&item=an_item
My question is, what do I have to do - specifically in WebAppConfig.Register and in the controller - in order to serve the above requests (assuming my test URL is correct...)?
You're getting tripped up by Web API conventions for matching a controller name in a URL to a controller class.
If the name of your controller is "MyController", then the URL to request is:
http://localhost:22332/api/my/authorize?user=ury&session=token&item=an_item
To support a request w/o the "api" bit in the URL, simply add a second route definition in the Register method of WebApiConfig.cs. Since you're also using "actions" in your URL's, you'd need these two routes:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "RootWebApiRoute",
routeTemplate: "{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
If you want to omit the "api" prefix as well as the controller parameter, I think you need a different route definition. Something like:
public static void Register(HttpConfiguration config) {
config.Routes.MapHttpRoute(
name: "ActionOnlyRoute",
routeTemplate: "{action}",
defaults: new { controller = "My" }
);
}
Here, we'll only look for an "action" in the URL and route everything to your "MyController" class.
After a few hours working on this and with a lot of help from the Route Debugger - Thanks Phil Haack! - I've found both the problem and the solution.
The problem: Route mapping matching is ordered, and RouteTable.Routes, from which the app's route mapping is initialized, contains quite a few of them. The request pattern I was looking for also matched some of these mappings ("authorize" was matched as a controller, for example).
The solution: add "my" route mappings before the default mappings.
Yeah, right...
Since most operations are not supported on HttpRouteCollection, the resulting code is a bit ugly, but it works:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
routesCopy = new RouteBase[RouteTable.Routes.Count];
RouteTable.Routes.CopyTo(routesCopy, 0);
config.Routes.Clear();
config.Routes.MapHttpRoute(name: "AuthorizeWebApiRoute", routeTemplate: "authorize", defaults: new { controller = "My", action = "authorize" });
config.Routes.MapHttpRoute(name: "ReleaseWebApiRoute", routeTemplate: "release", defaults: new { controller = "My", action = "release" });
foreach (var route in routesCopy)
{
RouteTable.Routes.Add(route);
}
}
}
As long as "my" route mappings don't match the default mappings (I made them specific enough not to), I'm all good - I think...

Resources