getting 404 for get api controller result after changing startup to OWIN - asp.net-web-api2

I start with Empty asp.net web api application with all default settings for VS 2017. I added one controller method with httpGet and result is fine.
Now I installed Microsoft.Owin.Host.SystemWeb and added a OWIN Startupclass.
[assembly: OwinStartup(typeof(WebApp1.Startup))]
namespace WebApp1
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
After that I comment out global.asax code as I believe I don't need it,
protected void Application_Start()
{
//GlobalConfiguration.Configure(WebApiConfig.Register);
}
Removing as well below code for Web API routes
//public static class WebApiConfig
//{
// public static void Register(HttpConfiguration config)
// {
// // Web API configuration and services
// // Web API routes
// config.MapHttpAttributeRoutes();
// config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "api/{controller}/{id}",
// defaults: new { id = RouteParameter.Optional }
// );
// }
//}
Now I'm getting 404 error while accessing the API, my OWIN startup code also calling. Whats wrong here? please suggest!.

You have to add the following line of code at the end of your OWIN Configuration method:
app.UseWebApi(config);
Note: this method is located in:
using Owin; //Assembly System.Web.Http.Owin

Related

Route Attribute not working in Web API 2

I have two GET methods on my API controller. When I attempt to call the GetByCompanyId method, which I have decorated with the Route Attribute, the request instead is being routed to the GetById method. Below are the relevant code files.
global.ascx.cs
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);
}
}
webApiConfig
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.EnableCors();
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
route.config
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
CompanyFunctionsController.cs
public IHttpActionResult GetById(int id)
{
var companyFunction = this._service.GetByKey(new object[] { id });
if (companyFunction != null)
{
var companyFunctionDto = Mapper.Map<CompanyFunctionDto>(companyFunction);
return Ok(companyFunctionDto);
}
return NotFound();
}
[Route("CompanyFunctions/GetByCompanyId", Name = "GetByCompanyId")]
[HttpGet]
public IEnumerable<CompanyFunctionDto> GetByCompanyId(int id)
{
var collection = this._service.GetAll().ToList().Where(x => x.CompanyId == id);
IEnumerable<CompanyFunctionDto> collectCompanyFunctionDtos = Mapper.Map<IEnumerable<CompanyFunctionDto>>(collection);
return collectCompanyFunctionDtos;
}
My HTTP request:
http://localhost:1317/api/CompanyFunctions/GetByCompanyId?id=1
If you want to have a route that starts with api like http://localhost:1317/api/CompanyFunctions/GetByCompanyId?id=1 then you must use the string api in your route attribute that you want it to go to.
[Route("api/CompanyFunctions/GetByCompanyId", Name = "GetByCompanyId")]
Otherwise it will only match based on the http verb (Get in this case).
Alternatively you can decorate the web api controller with the [RoutePrefix("api/CompanyFunctions")] attribute as well and change your Route attribute to [Route("GetByCompanyId", Name = "GetByCompanyId")]
Web API 2 supports a new type of routing, called attribute routing. As the name implies, attribute routing uses attributes to define routes. Attribute routing gives you more control over the URIs in your web API
You might use Attribute Routing in Web Api to solve your problems. Your Controller Action should be like this,
[Route("CompanyFunctions/GetByCompanyId/{companyId}"]
public IEnumerable<CompanyFunctionDto> GetByCompanyId(int companyId)
{
var collection = this._service.GetAll().ToList().Where(x => x.CompanyId == companyId);
IEnumerable<CompanyFunctionDto> collectCompanyFunctionDtos = Mapper.Map<IEnumerable<CompanyFunctionDto>>(collection);
return collectCompanyFunctionDtos;
}
and your HTTP request is http://localhost:1317/CompanyFunctions/GetByCompanyId/1

Visual Studio MVC4 Auto Url Routing for All Url's

Hello everyone I am working with VS13 MVC4 in localhost, for url routing I want VS will work for all url's automatically as www.sitename.com/about-us but now it is getting underscore (_) not dash (-) how to make a change and get hyphen(-) before every new word in url
Here is the answer I also add it to my question for everyone can see:
public class HyphenatedRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.RouteData.Values["controller"] = requestContext.RouteData.Values["controller"].ToString().Replace("-", "_");
requestContext.RouteData.Values["action"] = requestContext.RouteData.Values["action"].ToString().Replace("-", "_");
return base.GetHttpHandler(requestContext);
}
}
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add(
new Route("{controller}/{action}/{id}",
new RouteValueDictionary(
new { controller = "Default", action = "Index", id = "" }),
new HyphenatedRouteHandler())
);
}
}
Thanks everyone.
If you want pretty url in asp.net mvc then you should go by registering new route for your controller.
from the application directory open RouteConfig.cs in the App_Start directory.
And in the RegisterRoutes method of RouteConfig class register a new route like this-
routes.MapRoute(
name: "AboutUs",
url: "sitename/about-us",
defaults: new { controller = "About_Us", action = "Index" }
);
The _ will prob be automatically converted to a - in the routing. The other way is to set up the routing yourself

Add Web Api controllers to an existing ASP.NET 4 web application

Following the steps from this question How to add Web API to an existing ASP.NET MVC 4 Web Application project? , I have added web api support to my application.
In my original scenario I have the following web mvc controller:
public class FranchiseController : Controller
{
public ActionResult List()
{
return View();
}
[DataContext]
public ActionResult GetAllFranchises()
{
var franchiseInfoViewModelList = new List<FranchiseInfoViewModel>();
var franchiseInfoList = _franchiseService.GetAll();
foreach (var franchiseInfo in franchiseInfoList)
{
franchiseInfoViewModelList.Add(new FranchiseInfoViewModel(franchiseInfo, p => p.IsImportant));
}
var jsonNetResult = new JsonNetResult
{
Formatting = Formatting.Indented,
Data = franchiseInfoViewModelList
};
return jsonNetResult;
}
}
When the user navigates to the List view, I am calling
$.getJSON("/franchise/GetAllFranchises")
.done(function (data) {
});
to go to the GetAllFranchises action method and return the json data. So far so good.
I have created the following web api controller:
public class FranchiseController : ApiController
{
public IEnumerable<FranchiseInfoViewModel> GetAllFranchises()
{
var allFranchises = new List<FranchiseInfoViewModel>();
var franchiseInfoList = _franchiseService.GetAll();
foreach (var franchiseInfo in franchiseInfoList)
{
allFranchises.Add(new FranchiseInfoViewModel(franchiseInfo, p => p.IsImportant));
}
return allFranchises;
}
}
and I am trying to get to its action method like this:
$.getJSON("api/franchise")
.done(function (data) {
});
I am getting 404 error and the app is trying to reach the following url:
/Franchise/api/franchise
instead of api/franchise.
Global Asax:
protected void Application_Start()
{
Log.StartSession();
ElmahExtension.SetCurrentApplication(this);
ViewEngines.Engines.Add(new OmegaViewEngine());
AreaRegistration.RegisterAllAreas();
SerializerConfig.Register(GlobalConfiguration.Configuration);
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
Bootstrapper.Initialise();
FluentValidationModelValidatorProvider.Configure();
}
Default route:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
In my Controllers folder I have my web mvc controller:
Controller\FranchiseController
and I have made a new folder WebAPI to hold my web api controller
Controller\WebAPI\FranchiseController
What am I doing wrong ? Thanks!
I'm not sure if it's the right move to name "FranchiseController" both to the MVC Internet Application Controller and to the MVC Web API Controller (totally different things). After renaming one of them I think you should put the Web Api Controller in the root of the directory (Controller).

MVC 4.5 Web API Routing not working?

The 1st route works.
e.g. api/Shelves/SpaceTypes/1
The 2nd route doesn't work. I get multiple actions error.
e.g api/Shelves/1
Q) Why?
These are my routes:
config.Routes.MapHttpRoute(
"DefaultApiWithAction",
"api/{controller}/{action}/{id}"
);
config.Routes.MapHttpRoute(
"DefaultApiWithId",
"api/{controller}/{id}",
null,
new { id = #"\d+" }
);
This is my controller:
public HttpResponseMessage Get(int id)
{
...
}
[ActionName("SpaceTypes")]
public HttpResponseMessage GetSpaceTypes(int id)
{
...
}
For MVC 4.5 this is the only thing that works
There is currently a bug about this.
In order to get your routing to work so the following work
api/Shelves/ //Get All Shelves
api/SpaceTypes/1 //Get Shelf of id 1
api/Shelves/1/SpaceTypes/ //Get all space types for shelf 1
you need to do the following.
Change your routing over to. (Note the default action..)
config.Routes.MapHttpRoute(
name : "DefaultAPi",
routeTemplate : "api/{controller}/{id}/{action}",
defaults: new {id= RouteParameter.Optional,
action = "DefaultAction"}
);
In your controller change the base methods over to
[ActionName("DefaultAction")]
public string Get()
{
}
[ActionName("DefaultAction")]
public string Get(int id)
{
}
[ActionName("SpaceTypes")]
public string GetSpaceTypes(int id)
{
}
Now everything should work as expected..
Thanks to Kip Streithorst full this, for a full explanation
I had a similar issue and discovered i wasn't calling MapHttpAttributeRoutes method in my WebApiConfig...
hope it helps,
David
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
#Kristof is almost right. You should make your second route:
config.Routes.MapHttpRoute(
"DefaultApiWithId",
"api/{controller}/{id}",
new { action = "Get" },
new { id = #"\d+ }
);
This route does not know which action to bind to :
config.Routes.MapHttpRoute("DefaultApiWithId", "api/{controller}/{id}", null, new { id = #"\d+" });
Both of your methods are a valid candidate.
I'm not 100% clear what your setup is but in normal REST every resource has a controller, it seems like you have 1 controller with 2 resources.
To make it work in this setup you could force your second route to the get action like this :
config.Routes.MapHttpRoute("DefaultApiWithId", "api/{controller}/{id}", null, new { id = #"\d+", action="Get" });
Make sure in your project's Global.asx file, that you've added
WebApiConfig.Register(GlobalConfiguration.Configuration);
into the Application_Start function.

404 trying to use web api endpoint

I'm trying to add a web api controller to my MVC project. It's an MVC 3 project that I've upgraded to MVC4. I'm trying to get the "test" simple api controller to work, and currently getting a 404. Here's what I've done:
I've added all the required packages.
I've added my webapi config to my Global Application_Start():
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
WebApiConfig.Register(GlobalConfiguration.Configuration); // Web API
This then calls my static Register method:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
I have a ApiController defined in my web app:
public class SitechangesController : ApiController
{
/// GET api/default1
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
And finally, when I build it all and browse to my site on localhost http://localhost/api/Sitechanges , I get a 404.
If I do a file/new project and create a web api project from scratch, I don't have these problems. Can anyone help?
Thanks
Matt
It seems adding the web api config before the "normal" routes fixes it!
WebApiConfig.Register(GlobalConfiguration.Configuration); // Moved to the top
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
Your controller must end in ...Controller.cs.
For example:
Test.cs and TestControllerV2.cs will return 404.
TestController.cs and TestV2Controller.cs will return 200.
I see yours does, but I came across your post when searching for why a 404 was returned.