Add Web Api controllers to an existing ASP.NET 4 web application - asp.net-mvc-4

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).

Related

I cant show the API versions in response header with ApiVersioning .net Core

I follow the instruction REST API versioning with ASP.NET Core to show My API version in the response header.
This is my Configuration code:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddMvc().AddNewtonsoftJson();
services.AddMvc(opt =>
{
services.AddRouting(env => env.LowercaseUrls = true);
services.AddApiVersioning(opt => {
opt.ApiVersionReader = new MediaTypeApiVersionReader();
opt.AssumeDefaultVersionWhenUnspecified = true;
opt.ReportApiVersions = true;
opt.DefaultApiVersion = new ApiVersion(1, 0);
opt.ApiVersionSelector = new CurrentImplementationApiVersionSelector(opt);
});
}
and this is my Controller :
[Route("/")]
[ApiVersion("1.0")]
public class RootController:Controller
{
[HttpGet(Name =nameof(GetRoot))]
public IActionResult GetRoot()
{
var response = new { href = Url.Link(nameof(GetRoot),null) };
return Ok(response);
}
}
when I test my API with postman I got this result :
I don't know why opt.ReportApiVersions = true; doesn't work.
The reason why it behaves this way is to disambiguate an API controller from a UI controller. In ASP.NET Core, there's not really any other built-in way to do so as - a controller is a controller.
There are a few other ways to change this behavior:
Opt out with options.UseApiBehavior = false as the was the case before [ApiController]
Add a custom IApiControllerSpecification that identifies an API controller (there's a built-in implementation that understands [ApiController])
Replace the default IApiControllerFilter service, which is really just an aggregation over all registered IApiControllerSpecification implementations
I hope that helps
I found the solution. I have to add [ApiController] to my Controller:
[Route("/")]
[ApiVersion("1.0")]
[ApiController]
public class RootController:Controller
{
[HttpGet(Name =nameof(GetRoot))]
public IActionResult GetRoot()
{
var response = new { href = Url.Link(nameof(GetRoot),null) };
return Ok(response);
}
}

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

MVC4 how to set default url?

I'm working on building a MVC4 web app and want to set specific URL I would like to use in the start point of my web application.
So I changed some values in RouteConfig.cs like this below.
routes.MapRoute(
name: "Default",
url: "{action}.mon/{id}",
defaults: new { controller = "login", action = "index", id = UrlParameter.Optional }
);
you may notify this, but I put a suffix after action name, so that I could invoke a controller, displaying the URL like " index.mon "
if I manually put "index.mon" after host address in URL bar, then it works just okay.
But when the app gets started automatically, it throws 403.14 error. ( "automatically start" means here that I ran this app by putting F5 key to run a temporary IIS server. )
the login controller looks like this
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.OleDb;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Monarch815MVC.Controllers
{
public class loginController : Controller
{
//
// GET: /login/
public ActionResult index()
{
return View();
}
public ActionResult loginProcess(string id = "000000", string pass = "example", string scode = "co")
{
Dictionary<string, object> sessionData = null;
String SqlCommand = "USP_LOGIN";
DataSet UserInfo = dataController.ExecuteDataset(dataController.CONN_STRING, CommandType.StoredProcedure, SqlCommand, arParms);
if (UserInfo.Tables[0].Rows.Count > 0)
{
sessionData = new Dictionary<string, object>();
for (int i = 0; UserInfo.Tables[0].Rows[0].Table.Columns.Count > i; i++)
{
sessionData.Add(UserInfo.Tables[0].Rows[0].Table.Columns[i].Caption, UserInfo.Tables[0].Rows[0].ItemArray[i]);
}
}
return View();
}
}
}
( let's forget about the loginProcess, I took off a few codes. )
Do I have to do something on returning phase in index() or on Web.config? or, RouteConfig.cs?
I have to use the suffix ".mon" to invoke controllers with it.
I could think of solving this issue by only using a hack. You might want to create a dummy action which will be the default action and upon being hit will redirect the request to your index.mon
i tried following, Please check if this helps you. Thanks.
In the route config
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "DefaultY",
url: "{action}-mon/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "DefaultX2",
url: "{action}/{id}",
defaults: new { controller = "Home", action = "Startup", id = UrlParameter.Optional }
);
}
In controller
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Startup()
{
return RedirectToRoute("DefaultY", new {controller = "Home", action = "Index" });
}
}
For me i used index-mon. index.mon was not working (something which i'l explore later, perhaps it relates to static files), but above code demonstrates the approach.
Hope that helps.

ASP MVC default route is not applying for root site url

I'm having trouble getting ASP.net MVC to serve up the default controllers index view for the root site url http://mysite:8080/. All I get back is a 404 with The resource cannot be found. It works fine if I specify the full route path in the url : http://mysite:8080/Default/Index, however, I want the default route to apply even if the user doesn't specify the route path though. It seems that this should just work out of the gate. This is a fresh project from the VS2013 MVC 4 template.
I've tried both route mappings below and neither seems to work. How can this be achieved?
routes.MapRoute(
"Root",
"",
new { controller = "DefaultController", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "DefaultController", action = "Index", id = UrlParameter.Optional }
);
Here is a solution to this problem. It's disappointing that the default route's defaults do not apply for the root site url though.
routes.Add(new Route("", new SiteRootRouteHandler("~/Default/Index")));
public class SiteRootRouteHandler : IRouteHandler
{
private readonly string _redirectUrl;
public SiteRootRouteHandler(string redirectUrl)
{
_redirectUrl = redirectUrl;
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new SiteRootHandler(_redirectUrl);
}
}
public class SiteRootHandler: IHttpHandler
{
private readonly string _redirectUrl;
public SiteRootHandler(string redirectUrl)
{
_redirectUrl = redirectUrl;
}
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.RedirectPermanent(_redirectUrl);
}
}

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.