I am trying to get a web api set up that will use RESTful services. I am following this guide.
Getting Started with ASP.NET Web API 2 (C#)
I am also following this guide for setting up Entity Framework.
Getting Started with Entity Framework 6 Code First using MVC 5
When I run a Composer in Fiddler. I get the webpage for Home.aspx
Here is the code for my controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using WebServer.z_Repository;
using WebServer.z_Models;
namespace WebServer.z_Controllers
{
[Route("api/Locations")]
public class LocationsController : ApiController
{
// GET api/<controller>
static IlocationsRepository LocationsRepo;
public LocationsController(IlocationsRepository _repo)
{
if (_repo == null) { throw new ArgumentNullException("_repo"); }
LocationsRepo = _repo;
}
[HttpGet]
public IEnumerable<Location> GetAll()
{
return LocationsRepo.GetAll();
}
}
}
I put a breakpoint on the GetAll() and that breakpoint was never hit. This tells me that the controller isn't registered somewhere. But the guide doesn't say anything about where it should be registered.
I created a Global.asax.cs page even though this is not in the guide. But I am unsure of where to go from here.
Code for Global.asax.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
namespace WebServer
{
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
}
protected void Session_Start(object sender, EventArgs e)
{
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
}
}
}
Here is a snippet showing the response in the Fiddler
Home is showing because according to the URL you showed in Fiddler:
GET Home.aspx/api/locations
it is being told to go to Home.aspx
You are using attribute routing but have not shown any setup for it.
Reference: Attribute Routing in ASP.NET Web API 2
Your controller should be:
[RoutePrefix("api/Locations")]
public class LocationsController : ApiController
{
IlocationsRepository locationsRepo;
public LocationsController(IlocationsRepository _repo)
{
if (_repo == null) { throw new ArgumentNullException("_repo"); }
this.locationsRepo = _repo;
}
//GET api/locations
[HttpGet]
[Route(""}]
public IEnumerable<Location> GetAll()
{
return locationsRepo.GetAll();
}
}
Your WebApiConfig.cs:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Attribute routing.
config.MapHttpAttributeRoutes();
// Convention-based routing.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
and in your global, include
protected void Application_Start()
{
// Pass a delegate to the Configure method.
GlobalConfiguration.Configure(WebApiConfig.Register);
}
Now in order to hit locations web api you will need to call
GET api/location
Host: localhost:59104
which works out to http://localhost:59104/api/locations
Related
I created a Web API (Microsoft.AspNet.WebApi v5.2.7) targeted to .NET Framework 4.6.2 within a single project that included the default Help page MVC (Microsoft.AspNet.Mvc v5.2.7).
I created an ApiController to handle regular HTTP requests
using System.IO;
using System.Net;
using System.Threading;
using System.Web.Http;
using Project1.Models;
namespace Project1.Controllers
{
public class ProjectController : ApiController
{
// ... code ...
}
}
I eventually needed to self-host it in a Windows service. I was able to do this with OWIN (Microsoft.AspNet.WebApi.OwinSelfHost v5.2.9) by creating a second project, Project2, and adding Project1 as a reference in it. Project2 uses a startup like this
using System;
using System.Web.Http;
using Owin;
using Project1;
namespace Project2.Service
{
public class Startup
{
// reference controller so it's discoverable and can be used by service
Type projectControllerType = typeof(Project1.Controllers.ProjectController);
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
}
The service itself for Project2 is basic for this type of project. It starts and stop the web app disposable.
using System;
using System.ServiceProcess;
using Microsoft.Owin.Hosting;
namespace Project2.Service
{
public partial class Project2Service : ServiceBase
{
public string BaseAddress = "http://+:65432/";
private IDisposable _server = null;
public Project2Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
_server = WebApp.Start<Startup>(url: BaseAddress);
}
protected override void OnStop()
{
if (_server != null)
{
_server.Dispose();
}
base.OnStop();
}
}
}
Now I wanted to add a /Help route, which comes with WebApi project in the Areas directory
Is there a way to implement this and make the help page callable from my self-hosted service?
I found in the Global.asax it calls AreaRegistration.RegisterAllAreas().
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace Project1
{
public class WebApiApplication : 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);
}
}
}
I tried calling the AreaRegistration from the service startup
using System.Web.Mvc;
namespace Project2.Service
{
public class Startup
{
// reference controller so it's discoverable and can be used by service
Type projectControllerType = typeof(Project1.Controllers.ProjectController);
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
AreaRegistration.RegisterAllAreas();
appBuilder.UseWebApi(config);
}
}
}
This would cause an exception of This method cannot be called during the application's pre-start initialization phase.
I'm not sure how to go about this. Can I even implement pages with a self-hosted WebAPI?
I am trying to set up a C# Web API that uses OData 4. I created an OdataController and believe I routed it correctly in the WebApiConfig. I put a debugger on each function in the controller to see if the request enters the method(s). When I hit GET http://localhost:10013/odata/Call the debugger in the first method hits but once I let the debugger move on the request fails. In Chrome I see the request returns with '406 Not Acceptable' but there is nothing in the preview or response tabs. What am I doing wrong? I can see that the request enters the controller correctly but why does it not return the string "call" as well as send a 406?
Secondly, if I send the request http://localhost:10013/odata/Call(0) the first method in the controller gets hit not the second (desired) or even the third. What am I doing wrong here if I want it to hit the second or third method?
I've included the controller and the WebApiConfig that I am using.
namespace JamesMadison
{
public static class Call
{
}
}
using System.Web.Http.OData;
namespace JamesMadison.Controllers
{
public class CallController : ODataController
{
public string GetCall()
{
return "call";
}
public string GetCall([FromODataUri] int id)
{
return "call";
}
public string GetCall([FromODataUri] string key)
{
return "call";
}
}
}
using System.Web.Http;
using System.Web.OData.Builder;
using System.Web.OData.Extensions;
namespace JamesMadison
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapODataServiceRoute("odata", "odata", model: GetModel());
}
public static Microsoft.OData.Edm.IEdmModel GetModel()
{
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Call>("Call");
return builder.GetEdmModel();
}
}
}
In the controller, I had using System.Web.Http.OData; and replaced it with using System.Web.OData;
I have upgrade aspx project to mvc. Now some of my old customer calling url with .aspx page and they are getting 404(not found) in mvc project.
So now I have to redirect .aspx to mvc page.
Old URL
www.domain.com/bookshop/showproduct.aspx?isbn=978-1-59333-934-0
New URL
www.domain.com/{product_name}
I am thinking to do via routing mechanism of mvc. like once this type of url come then it should be call my custom mvc action and in string parameter i will get showproduct.aspx?isbn=978-1-59333-934-0
Can you please suggest a best way to do this with minimal code.
Create a new class RouteHandler as shown below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;
namespace Sample.Helpers
{
public class RouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new ASPDotNetHttpHandler();
}
}
public class ASPDotNetHttpHandler : IHttpHandler
{
public bool IsReusable
{
get
{
return true;
}
}
public void ProcessRequest(HttpContext context)
{
string product = context.Request.QueryString["isbn"];
int index = context.Request.Url.AbsoluteUri.IndexOf("bookshop/showproduct.aspx?");
if (!(string.IsNullOrEmpty(product) || index == -1))
{
string newUrl = context.Request.Url.AbsoluteUri.Substring(0, index)+"/" + product;
context.Response.Redirect(newUrl, true);
}
}
}
}
Insert new route as shown below in RegisterRoutes method of RouteConfig.cs file:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add(new Route("bookshop/showproduct.aspx", new BIRS.Web.Helpers.RouteHandler()));
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.
I'm completely stuck on this - after commenting out almost everything to do with startup configuration leaving only the following, I still can't get the WebApi Attribute routing to work correctly.
I have the following Global.asax.cs:
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
The following controller - located in an area called "v2":
[RoutePrefix("v2/businesses")]
public class BusinessesController : ApiController
{
// GET: v2/businesses/{id}
[HttpGet]
[Route("{id:int}")]
public ApiResponse<ApiBusiness> Index(int id)
{
return new ApiResponse<ApiBusiness>(new ApiBusiness());
}
}
The following area registration:
public class V2AreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "v2";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.Routes.MapMvcAttributeRoutes();
}
}
And the following WebApiConfig:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
}
}
When I try to access the endpoint URL businesses/1 or v2/businesses/1 or v2/v2/businesses/1 all three return a 404, I was sure one of those would be correct.
Note that a different controller outside of the "v2" area works perfectly fine:
[RoutePrefix("abc")]
public class TestingController : ApiController
{
[HttpGet]
[Route("123")]
public int Test()
{
return 2;
}
}
Sure enough, 2 is returned when I access that endpoint (abc/123).
Can anyone explain why this isn't working?
In this situation you are saying that "v2" is both and mvc route AND a web api route; they can't coexist.
I mean, they can, but what happens here is that the requests to the web API will be mistakenly handled as if they were an MVC action. That's why you get a 404.
In less words, Web API doesn't really support areas. What you can do here is try to register the web api routing before the mvc routing or explicitly handle the web api rounting using MapHttpRoute. For example:
context.Routes.MapHttpRoute("AreaName_WebApiRoute",
"AreaName/Api/{controller}/{id}",
new { id = RouteParameter.Optional });
Check this SO answer for more details!