I have a web api that runs in a WPF C# application. I have used Owin to implement it. If I send request by using /api prefix then it works as I expected.
http://localhost:8080/api/test/config?no=7
However, I need to remove the /api prefix. If I try the request below it does not work when I tried example code below.
http://localhost:8080/test/config?no=7
Is it possible to remove api word from requests?
Here is my code:
WebApp.Start<Startup>(url: "http://*:8080/");
class Startup
{
Type ValuesControllerType = typeof(TestController);
public void Configuration(IAppBuilder Builder)
{
var Instance = new HttpConfiguration();
Instance.MapHttpAttributeRoutes();
Instance.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{action}/{request}",
defaults: new { request = RouteParameter.Optional }
);
Builder.UseWebApi(Instance);
}
}
[RoutePrefix("test")]
public class TestController : ApiController
{
[HttpGet]
[Route("config")]
public string Config(string No)
{
try
{
return No;
}
catch (Exception e)
{
return string.Empty;
}
}
}
I tried the answer in C# web api route for a webservice but did not work.
I get following error:
HTTP Error 503. The service is unavailable.
On the Rest api open your WebApiConfig.cs you should find the following code:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}"
);
Try removing api from there
I faced the same problem in .Net Core 2 WebAPI project
here is my solution
[Produces("application/json")]
[Route("[controller]")]
public class DefaultController : Controller
{
[Route("getUser")]
public IActionResult GetUsers()
{
return Ok();
}
}
the address is http://localhost:port/default/getuser
Related
I am having difficulties to understand how WebAPI routing is working. This is what my controller looks like:
[RoutePrefix("order-mgmt")]
public class OrderController : ApiController
{
[HttpGet]
[Route("execute")]
public HttpResponse ExecOrder(string clordid)
{
// ...
return Request.CreateResponse(HttpStatusCode.NoContent);
}
[HttpGet]
[Route("reject")]
public HttpResponse RejectOrder(string clordid)
{
// ...
return Request.CreateResponse(HttpStatusCode.NoContent);
}
}
And this is my Startup class and configuration
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
I was expecting that I am able to reach public HttpResponseMessage ExecOrder(string clordid) via http://localhost:port/api/order-mgmt/execute?clordid=<clordidstring>.
This however doesn't work. The controller is still only reachable via api/order/execute. I really don't get what I am doing wrong here. Any help is greatly appreciated.
try removing [RoutePrefix("order-mgmt")]
then do it like this
[Route("api/order-mgmt/execute/{clordid}")]
public HttpResponse ExecOrder(string clordid)
// then you can reach it in this route
// api/order-mgmt/execute/YOUR_STRING
I am using Owin self-hosting with WebAPI2.
I have two controller classes and using attribute routing.
One of them has following signature:
[RoutePrefix("api/v1/devices")]
public class DeviceController : ApiController
{
[HttpPost]
[Route("")]
public async Task<HttpResponseMessage> DevicePresence()
{
...
}
[HttpGet]
[Route("updates/{deviceID}")]
public HttpResponseMessage GetDeviceUpdates(string deviceID)
{
...
}
}
This one is working fine and action methods get triggered.
The other Controller has below signature:
[RoutePrefix("device/class")]
public class RemoteController : ApiController
{
[HttpGet]
[Route("remotehost")]
public HttpResponseMessage RemoteHost()
{
...
}
[HttpGet]
[Route("version")]
public HttpResponseMessage GetVersion()
{
...
}
}
When I try to connect to any of these I get 503 (Service Unavailable) response.
My Startup class is initialized as below:
public class Startup
{
public static void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Formatters.Add(new JsonMediaTypeFormatter());
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.EnsureInitialized();
app.UseWebApi(config);
}
}
I tried to use the conventional routing as well but still the same problem.
config.Routes.MapHttpRoute(
name: "RemoteApi",
routeTemplate: "device/{controller}/{action}"
);
public class ClassController : ApiController
{
public HttpResponseMessage GetVersion()
{
...
}
}
This is also throwing 503 status code
If I change the Route prefix in the second controller as below then it's working:
[RoutePrefix("api/v1/device/class")]
public class RemoteController : ApiController
{
...
}
As per my requirement, I couldn't change the endpoints.
I am not sure what's wrong here and any help would be much appreciated.
Your RemoteController throws an exception because you do not follow naming conventions of WEB API.
Your RemoteHost() method which is a get method has to have a "Get" prefix, so its name is supposed to actually be GetRemoteHost().
That should solve it.
In case you want to alter the naming conventions, you can modify route definitions in the global.asax file:
Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { action = "get", id = RouteParameter.Optional }
);
Hope that helped.
I realized it was not a problem with webapi or routing.
Actually, I was adding a firewall exception for the URL's and somehow it was not getting removed from firewall settings and keeps an entry in DACL.
I removed this from cmd prompt and now everything works fine.
Sorry for bothering...
When using the following routes:
config.Routes.MapHttpRoute(
name: "new_device",
routeTemplate: "api/v1/devices",
defaults: new { controller = "Devices", action = "new_device" }
);
config.Routes.MapHttpRoute(
name: "devices_list",
routeTemplate: "api/v1/devices",
defaults: new { controller = "Devices", action = "devices_list", httpMethod = new HttpMethodConstraint(HttpMethod.Get) }
);
The controller looks as follows:
public class DevicesController : ApiController
{
[HttpPost]
[ResponseType(typeof(IHttpActionResult))]
[Route("api/v1/devices")]
[ActionName("new_device")]
[ValidateModel]
public IHttpActionResult NewDevice([System.Web.Http.FromBody] Device device )
{
...
}
[HttpGet]
[ResponseType(typeof(IHttpActionResult))]
[Route("api/v1/devices")]
[ActionName("devices_list")]
[ValidateModel]
public List<Device> GetAllDevices()
{
...
}
My expectation would be that the router would find the correct route based on the HttpMethod used since even it's using the same URI it is using a different HttpMethod.
But instead it fails with the following:
"Message": "The requested resource does not support http method 'GET'."
My guess is because it fins a match with the URI and then checks if the method if the same.
Is there a way to achieve using the same URI with different Http Method which is by the way REST guidelines? Am I missing something?
Ok , I check your whole code. I think you are trying to achieve the calls in complicated way.
Following code is for the configuration :
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/v1/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
and follwoing is your controller code :
public class DevicesController : ApiController
{
[HttpPost]
[ResponseType(typeof(IHttpActionResult))]
[ActionName("newDevice")]
public IHttpActionResult NewDevice([System.Web.Http.FromBody] Device device)
{
return null;
}
[HttpGet]
[ResponseType(typeof(IHttpActionResult))]
[ActionName("devices_list")]
public List<Device> GetAllDevices()
{
return null;
}
}
I removed ValidateModel. I think it's your custom attribute or somehow related with built in nuget package.
Anyways, execute the calls with Postman or any HTTP client tool. It should work , as it was working at my end with above mentioned code.
Example Calls:
https://localhost:44370/api/v1/devices/devices_list = > Get.
https://localhost:44370/api/v1/devices/newDevice => Post. Provide body as post call for the object.
I have two web API project DLLs in one solution.
Structure of my Project Solution:
In my solution, the projects are located as follows:
1) Base Solution
2) Base Web API
3) Module Web API
Hence, my solution is something like a BASE solution which contains many MODULES. Each Modules can contain its own Web APIs. Also, my Base Solution contains its own Web API
This is our structure.
My Problem:
It is working fine in my local run solution. When I host it to the IIS, it is working for few hours and then it stops working by throwing the error message "Error 404 found". When I try to access through URL directly which is something like "http://127.0.0.1:51/Products/Get", not working.
Visual Studio version:
Visual Studio Professional - 2015
IIS Version:
IIS - 7.5.7600
My approach:
I have a simple project which simulates this scenario. It has the same problem with my original project.
Web API For Base Module:
WepApiConfig under App_Start:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Base API Controller:
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
}
WebApiConfig.cs For Module Web API:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
//config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultModuleApi",
routeTemplate: "api/module/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Module API Controller:
public class ModulesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
}
NOTE from the above code:
The difference between the two APIConfig files is :
For Module Code:
routeTemplate: "api/module/{controller}/{action}/{id}"
For Base Code:
routeTemplate: "api/{controller}/{action}/{id}"
Global.asax:
namespace BaseSln
{
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
//GlobalConfiguration.Configure(WebApiConfig.Register);
var typesWithMyAttribute =
from a in AppDomain.CurrentDomain.GetAssemblies()
from t in a.GetLoadableTypes().Where(t1 => t1.Name == "WebApiConfig"
&& t1.GetMethod("Register") != null
&& t1.GetMethod("Register").IsStatic)
select new { Type = t, MethodInfo = t.GetMethod("Register") };
//register all the Routes
foreach (var type in typesWithMyAttribute)
{
var mi = type.MethodInfo;
Action<HttpConfiguration> action = null;
try
{
action = Delegate.CreateDelegate(typeof(Action<HttpConfiguration>), mi) as Action<HttpConfiguration>;
}
catch
{
//ignore the errors for now... should be handled somewhere else or logged.
}
if (action != null) GlobalConfiguration.Configure(action);
}
}
}
}
What I tried with the above project:
After hosting in IIS, I tried to access the path which is something like this:
For Base API:
http://localhost:51600/api/Values/Get
Returns:
value1
value2
For Module API
http://localhost:51600/api/Modules/Get
Returns:
value1
value2
My problem:
After sometime, when I try to access the same link, I am unable to get that. It says
status 404. Not Found
I have been working on this issue for 3 days, and I couldn't resolve the problem.
I have searched many articles in stackoverflow, but no luck.
Kindly help me to get rid off from this.
Thanks.
Can you check the GlobalConfiguration.Configuration.Routes in the Base Solution if you have all the routes for both the Base Web API and the Module Web API?
I am developing a web api but it can not hit it. Error shows 404 not Found.
Web Api
using Atea.Azure.ApiMangement.Business;
using System.Web.Http;
namespace Azure_API_Delegation_Portal.Controllers
{
[RoutePrefix("api/apim")]
public class ApimController : ApiController
{
private readonly ISubscriptionService _subscriptionService;
[HttpGet]
[Route("{string:productId}")]
public bool GetProductSubscribe(string productId)
{
return _subscriptionService.IsSubscribed(productId);
}
}
}
How I call an API https://localhost:44300/api/apim/ldkjfk232
Web API Route
using System.Web.Http;
namespace Azure_API_Delegation_Portal
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
Image
I am missing this line of code in Application_Start() function in "Global.asax" file.
GlobalConfiguration.Configure(WebApiConfig.Register);
Fix your route template. It is string by default so no need for the string constraint
//GET api/apim/ldkjfk232"
[HttpGet]
[Route("{productId}")]
public bool GetProductSubscribe(string productId)
Also note that the constraint goes after the placeholder name like this example
[Route("{paramaterName:int}")]
Read more about attribute routing here : Attribute Routing in ASP.NET Web API 2
It will show you how to properly configure your web api.