Web Api 2 route configuration with legacy asmx services in api folder - c#

I'm trying to add the Web Api functionality to an existing ASP.NET application. This should be something simple but I'v been stuck on this for hours. I've tried a bunch of things but no luck so far.
The app has several asmx services in "/api" folder. This somehow interferes with the web api routing. Ideally, I'd like to keep the existing services in the current place since there are external references to them.
Sample service:
/Api/ApiServ.asmx - I'm able to invoke the initial screen with the method list
The problem is when I try to invoke any method on one of the services e.g. /Api/ApiServ.asmx/ServMethod - I can't invoke this and I'm getting this response: "No HTTP resource was found that matches the request URI 'http://localhost:49415/api/apiserv.asmx/ServMethod'"
Here is what I have:
Global.asax:
public class WebApiApplication : HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
//RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
Sample service:
namespace WebApiTest.Api
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
[ScriptService]
public class ApiServ : WebService
{
[WebMethod]
public string ServMethod()
{
return "Test";
}
}
}
Web Api Config:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.IgnoreRoute("asmx", "api/{resource}.asmx/{*pathInfo}");
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Strangely enough, when I use a route debbuger it actually matches the asmx ignore route but the service method is not being hit. Any help appreciated!

I didn't actually figure out a proper fix as I ran out of time I had allocated for fixing this but since the solution is temporary and will be moving the asmx services to web api controllers I decided to settle for a workaround.
This is what I did:
1) In the /Api folder I created a /Legacy subfolder and moved all asmx services there
2) In global.asax Application_BeginRequest:
private void Application_BeginRequest(object sender, EventArgs e)
{
string url = Request.Url.AbsolutePath.ToLower();
if (url.StartsWith("/api") && url.Contains(".asmx") && !url.Contains("/api/legacy/"))
{
url = Request.Url.AbsolutePath.Replace("/api/", "/api/legacy/");
Context.RewritePath(url);
}
}
Note a similar thing could be achieved in a more cultured way such as using the rewrite module but this works for me a temporary solution.

If you do have an mvc portion to your API (web api help pages will add mvc)
you will need to add the following line to your RouteConfig.cs:
routes.IgnoreRoute("{resource}.asmx/{*pathInfo}");
and that will do the trick!

Related

Using RouteAttribute and IIS Application gives 404 error

I have created a webAPI project and I would like to start hosting it in IIS.
The method in the controller looks like this:
[TokenAuthentication]
[HttpGet]
[Authorize(Roles=Roles.PING)]
[Route("~/Ping")]
public DateTime Ping()
{
return DateTime.UtcNow;
}
My WebApiConfig looks like this:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
config.MapHttpAttributeRoutes();
GlobalConfiguration.Configuration.Filters.Add(new ValidateModelAttribute());
//config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "{controller}/{id}",
// defaults: new { id = RouteParameter.Optional }
//);
}
}
When I run the project via visual studio, and go to the link http://localhost:53722/ping I get an unauthorized response which is what I expect.
When I put the website on IIS in an applicaion with the virtual path "/Account" I get a 404 response and it is trying to use the StaticFile Handler.
Through searching online I have runAllManagedModulesForAllRequests set to true. I have also found Configure ASP.NET Web API application as a Virtual Directory under ASP.NET MVC application which seems like the "/Account/" should not be interfering with the route.
I can not put the API at the route directory because I will be running multiple microservices under the same site.
How would I get the route to work using the virtual directory?
Thanks,
Steven
Each site should be running as an Application and not a Virtual Directory (and ideally with each having its own application pool).
Out of the box you would normally go for
[Route("ping")]
This would give you a url of http://blah.com/ping
If you are running this api in a sub folder/application then it maybe something like http://blah.com/subapp/ping
This is all i have...

Web Api 2 Routing Issue: "No action was found on the controller..."

I am having the issue of getting a 404 on my web api routing. Although there are many posts about this issue, they mainly seem to be about changing the order of the routes so that the MVC routes don't override the api routes.
I have tried all of the solution I have come across yet nothing seems to fix my issue.
Here is my controller:
[RoutePrefix("api/paving-designer")]
public class PavingDesignerController : ApiController
{
[HttpGet]
[Route("get-forms/{userId}")]
public IHttpActionResult GetForms(Guid userId)
{
ICollection<PavingDesignerFlatForm> forms = _helper.GetForms(userId);
if (forms != null)
{
return Ok(forms);
}
else
{
return NotFound();
}
}
}
And this is my Web Api Config
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new
{
id = RouteParameter.Optional
});
}
}
and this is my global asax
private void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
// RouteConfig.RegisterRoutes(RouteTable.Routes);
// Initialize Castle & install application components
_bootstrapper = CastleInitialiser.Initialise();
}
As you can see I have even tried to comment out the mvc routes to see if that made a difference
If I browse to http://localhost/api/paving-designer/get-forms/c6c489a7-46c6-420e-9e39-56797c8094cf
I get the following error:
No type was found that matches the controller named 'paving-designer'.
I have tried changing the route prefix to the following but to no avail
/api/paving-designer
/paving-designer
paving-designer
And if I browse to http://localhost/api/pavingdesigner/get-forms/c6c489a7-46c6-420e-9e39-56797c8094cf
I get the following error:
Multiple types were found that match the controller named 'pavingdesigner'. This can happen if the route that services this request ('api/{controller}/{action}/{id}') found multiple controllers defined with the same name but differing namespaces
I don't see how I can have multiple controllers as this is the only one I have.
Can anyone see where I am going wrong?
You are using both routing types.
Using attribute routing defined next route:
/api/paving-designer/get-forms/{userId}
Using default routing there is other route:
/api/{controller}/{action}/{id}
These routes are have the same template.
But using the first of them - ControllerSelector can not find paving-designerController.
Using the second - there is no action named get-forms. There are GetForms
If you remove one of them - it should work.
Ok in my particular case, the error was being caused as my IoC was registering the controller twice.
This was causing the duplicate entries, which in turn made the attribute routing fail.

GET requests work but POST requests 404 in Web API 2

I've got a project which uses MVC 5 and Web API 2. Locally, both HTTP GET and POST requests to the Web API controller are working. When the website is published and deployed to an external environment, the GET requests still work, but the POST requests result in a 404.
Here's my API controller:
public class ExampleApiController : ApiController
{
[HttpPost]
[Route("GetRoles")]
public IHttpActionResult GetRoles([FromBody] string userName)
{
// ...
return Json(response);
}
[HttpGet]
[Route("GetUsers")]
public HttpResponseMessage GetUsers()
{
HttpResponseMessage response;
// ...
return response;
}
}
Here's my WebApiConfig.cs file:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
config.Routes.MapHttpRoute(
name: "Web API default route",
routeTemplate: "api/{controller}/{action}",
defaults: null
);
}
}
Here's my Global.asax file:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
Some other notes:
I've verified that the POST request that the client is making is formatted correctly.
I added the following code to the Web.config:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
The environment I'm deploying my application out to has a subdomain which requires authentication (e.g. the URL looks something like http://qa.example.com). I am testing using (for instance) http://username:password#qa.example.com/GetUsers.
My controller is not using the RoutePrefix attribute.
Any ideas?
The issue was resolved - not super helpful for future readers, but the issue was related to a third-party security client on the server-side specifically blocking the request. Juliano's comment helped me in that direction of realizing this.
I would suggest use web API documentation (help page) or swagger to check your web api method actual url and parameter. you must missing something.
few day back I've face similar problem (post method working on local but not working on QA env.) but that time I was getting 405 error

How to add Web API to an existing ASP.NET MVC (5) Web Application project?

Assuming you forgot to tick the Web API checkbox (add it to the project) when making a new MVC (5) project, what do you need to do add Web API and get it working?
There are a bunch of migration questions, but none seemed to have the complete and up-to-date steps for adding Web API to an MVC 5 project and it seems to have changed from some of the old answers.
Add Web API to MVC 4
Adding GlobalConfiguration.Configure(WebApiConfig.Register) MVC 4
Update the MVC project
Use Nuget to get the newest Web API.
Project - Right click - Manage Nuget Packages - Search for Web API (Microsoft ASP.NET Web API ...) and install it to your MVC project.
Then you still need to get Web API routing to work.
From Microsoft's Configuring ASP.NET Web API 2
Add WebApiConfig.cs to the App_Start/ folder
using System.Web.Http;
namespace WebApplication1
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// TODO: Add any additional configuration code.
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// WebAPI when dealing with JSON & JavaScript!
// Setup json serialization to serialize classes to camel (std. Json format)
var formatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
formatter.SerializerSettings.ContractResolver =
new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
}
}
}
If you have an MVC Project it will have Global.asax.cs, add the new routes. Order of the Global.asax.cs routes is critical. Note there are outdated examples which use
WebApiConfig.Register
Add this line to Global.asax.cs:
GlobalConfiguration.Configure(WebApiConfig.Register);
protected void Application_Start()
{
// Default stuff
AreaRegistration.RegisterAllAreas();
// Manually installed WebAPI 2.2 after making an MVC project.
GlobalConfiguration.Configure(WebApiConfig.Register); // NEW way
//WebApiConfig.Register(GlobalConfiguration.Configuration); // DEPRECATED
// Default stuff
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
WebAPI Help
To get the (very) helpful WebAPI help pages, install WebAPI.HelpPage.
See http://channel9.msdn.com/Events/Build/2014/3-644 (~42 minutes in) for what it does. It looks very helpful!
Nuget Console: Install-Package Microsoft.AspNet.WebApi.HelpPage
To verify WebAPI is working:
To the controllers folder -> Add new item -> Web API Controller Class.
public class TestController : ApiController
{
//public TestController() { }
// GET api/<controller>
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/<controller>/5
public string Get(int id)
{
return "value";
}
//...
}
Now you can test in IE/FF/Chrome as usual, or in the JavaScript consoles for non-get testing.
(With just the controller in the URL it will call the GET() action in the new Web API Controller, it's automatically mapped to methods/actions depending on the REST e.g. PUT/POST/GET/DELETE. You don't need to call them by action like in MVC)
The URL directly:
http://localhost:PORT/api/CONTROLLERNAME/
Alternatively use jQuery to query the controller.
Run the project, Open the console (F12 in IE) and try run an Ajax query. (Check your PORT & CONTROLLERNAME)
$.get( "http://localhost:PORT/api/CONTROLLERNAME/", function( data ) {
//$( ".result" ).html( data );
alert( "Get data received:" + data);
});
Side note: There are some pros/cons to consider when combining MVC and Web API in a project
WebAPI Help verification:
http://localhost:PORT/help

Web Api Controller in other project, route attribute not working

I have a solution with two projects. One Web Api bootstap project and the other is a class library.
The class library contains a ApiController with attribute routing.
I add a reference from web api project to the class library and expect this to just work.
The routing in the web api is configured:
config.MapHttpAttributeRoutes();
The controller is simple and looks like:
public class AlertApiController:ApiController
{
[Route("alert")]
[HttpGet]
public HttpResponseMessage GetAlert()
{
return Request.CreateResponse<string>(HttpStatusCode.OK, "alert");
}
}
But I get a 404 when going to the url "/alert".
What am I missing here? Why can't I use this controller? The assembly is definitely loaded so I don't think http://www.strathweb.com/2012/06/using-controllers-from-an-external-assembly-in-asp-net-web-api/ is the answer here.
Any ideas?
Try this. Create a class in your class library project that looks like this,
public static class MyApiConfig {
public static void Register(HttpConfiguration config) {
config.MapHttpAttributeRoutes();
}
}
And wherever you are currently calling the config.MapHttpAttributeRoutes(), instead call MyApiConfig.Register(config).
One possibility is you have 2 routes on different controllers with the same name.
I had 2 controllers both named "UploadController", each in a different namespace and each decorated with a different [RoutePrefix()]. When I tried to access either route I got a 404.
It started working when I changed the name of one of the controllers. It seems the Route Attribute is only keyed on the class name and ignores the namespace.
We were trying to solve a similar problem.
The routes within the external assembly were not registering correctly.
We found one additional detail when trying the solution shown on this page.
The call to the external assembly "MyApiConfig.Register" needed to come before the call to MapHttpRoute
HttpConfiguration config = new HttpConfiguration();
MyExternalNamespace.MyApiConfig.Register(config); //This needs to be before the call to "config.Routes.MapHttpRoute(..."
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

Categories

Resources