ApiController Routing Isn't Working - asp.net-mvc-3

Below I'm going to insert the code for the following:
Global.asax
DatabasesController (ApiController)
The error I receive when trying to navigate to the default api route.
It is my understand that what I'm doing here is 100% correct, and in fact I've verified that the code lines up with an example I found from Mike Wasson. Hopefully you can show me the way to getting this working!
Thanks all!
Global.asax
Below is the code that exists in the Global.asax and this method is called by Application_Start() which was generated by the template.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
DatabasesController.cs
This is the ApiController, and it inherits from ApiController and was created by the template in Visual Studio. The databases field is declared as Database[] in the class.
public IEnumerable<Database> GetAllDatabases()
{
return databases;
}
public Database GetDatabaseById(string id)
{
return databases.Where(d => d.Name == id).FirstOrDefault();
}
Error
This is the error I'm receiving when I try to access it with what should be the default api path (as far as I understand it anyway...HA).
Server Error in '/' Application.
--------------------------------------------------------------------------------
Method not found: 'Void System.Net.Http.Headers.HttpHeaders.AddWithoutValidation(System.String, System.Collections.Generic.IEnumerable`1<System.String>)'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.MissingMethodException: Method not found: 'Void System.Net.Http.Headers.HttpHeaders.AddWithoutValidation(System.String, System.Collections.Generic.IEnumerable`1<System.String>)'.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:
[MissingMethodException: Method not found: 'Void System.Net.Http.Headers.HttpHeaders.AddWithoutValidation(System.String, System.Collections.Generic.IEnumerable`1<System.String>)'.]
System.Web.Http.WebHost.HttpControllerHandler.AddHeaderToHttpRequestMessage(HttpRequestMessage httpRequestMessage, String headerName, String[] headerValues) +0
System.Web.Http.WebHost.HttpControllerHandler.ConvertRequest(HttpContextBase httpContextBase) +248
System.Web.Http.WebHost.HttpControllerHandler.BeginProcessRequest(HttpContextBase httpContextBase, AsyncCallback callback, Object state) +79
System.Web.Http.WebHost.HttpControllerHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +48
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +268
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

It looks like you need to upgrade your version of webapi from beta to RC!

Related

Calling Web API from an aspx page is always resulting in Not Found error

I have a web site project ( the one that has an App_Code folder) which I have upgraded to .Net 4.5, and installed NuGet package for Web API 2.2 into the solution in VS 2013.
Under the root folder, there is a folder 'Vendors'. From a page under this folder, I am using jQuery to call a PUT Web API method inside a controller class 'AppsProcureWebApiController' under App_Code folder.
Using the url: 'api/AppsProcureWebApi' in ajax call from jQuery always results in a 'Not Found error'.
But if I hard-code the url as url:'http://localhost/appsprocure/api/AppsProcureWebApi' in same jQuery ajax call then it works and executes the code within the Web API method.
Question: Do I need to use some special routing configuration in global.asax to make it work with orginal url, Or there is something else I need to do? (code being used for configuring routing in global.asax is mentioned below).
jQuery for calling Web API from /Vendors/EditProduct.aspx page
function SaveProdDesc() {
var data = {
productId: $find("<%= radcomBoxProducts.ClientID%>").get_value(),
productDescription: $("#<%= txtProdDesc.ClientID%>").val(),
originalProductDescription: $("#<%= hfOrigProdDesc.ClientID%>").val()
}
$.ajax({
url: 'api/AppsProcureWebApi',
type: 'PUT',
data: JSON.stringify(data),
contentType: "application/json",
dataType:"json",
success: function (data) {
alert(data);
},
error: function (x, y, z) {
alert(x + '\n' + y + '\n' + z);
}
});
}
Routing defined in Global.asax
void Application_Start(object sender, EventArgs e)
{
//below code to make Web API work in Webforms
RouteTable.Routes.MapHttpRoute( name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional });
}
Web API controller class under App_Code is as below.
public class AppsProcureWebApiController : ApiController
{
//OTHER METHODS ARE OMITTED TO SAVE SPACE
[HttpPut]
[Authorize]
public int Put(ProductDesc p)
{
string prodDesc = p.ProductDescription;
return ApplicationDataAccess.UpdateProductDescription(p.ProductId, ref prodDesc, p.OriginalProductDescription);
}
}
public class ProductDesc
{
public long ProductId { get; set; }
public string ProductDescription { get; set; }
public string OriginalProductDescription { get; set; }
}
I found the answer after a lot of trying. This will be very useful in cases when using jQuery from an aspx page to call Web API in webforms asp.net projects, since in such projects the pages will exist under different folders.
Only a simple change is needed so the Web API can be called seamlessly from an aspx page under folder 'Vendors' using the url: 'api/AppsProcureWebApi'.
This simple change is of adding vendors to the routing configuration. If you let the original rule be there then make sure you name this new routing rule differently i.e. something other than DefaultApi. I have named this new rule as Rule1Api in code below.
So api/{controller}/{id} becomes vendors/api/{controller}/{id} in routing configuration as in code below. But do not change the url mentioned in jQuery call, which means let it be url: api/AppsProcureWebApi since vendors will be automatically prepended to the url mentioned in jQuery call.
void Application_Start(object sender, EventArgs e)
{
//below code to make Web API work in Webforms
RouteTable.Routes.MapHttpRoute( name: "Rule1Api",
routeTemplate: "vendors/api/{controller}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional });
}

SelfHosted AspNet WebAPI With Controller Classes In Different Project

I have created a SelfHosted AspNet WebAPI with Visual Studio 2012 (.NET Framework 4.5). I enabled SSL for the WebAPI. It works fine when the controller is defined in the same project.
But when I add a reference of another project, containing controllers, it gives me the following error:
No HTTP resource was found that matches the request URI 'https://xxx.xxx.xxx.xxx:xxxx/hellowebapi/tests/'.
I have created custom classes for HttpSelfHostConfiguration and MessageHandler.
Any help to resolve this problem would be a great time-savor for me.
Thanking in advance.
You can write a simple custom assemblies resolver which makes sure that your referenced assembly is loaded for the controller probing to work.
Following is a nice post from Filip regarding this:
http://www.strathweb.com/2012/06/using-controllers-from-an-external-assembly-in-asp-net-web-api/
Sample:
class Program
{
static HttpSelfHostServer CreateHost(string address)
{
// Create normal config
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(address);
// Set our own assembly resolver where we add the assemblies we need
CustomAssembliesResolver assemblyResolver = new CustomAssembliesResolver();
config.Services.Replace(typeof(IAssembliesResolver), assemblyResolver);
// Add a route
config.Routes.MapHttpRoute(
name: "default",
routeTemplate: "api/{controller}/{id}",
defaults: new { controller = "Home", id = RouteParameter.Optional });
HttpSelfHostServer server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();
Console.WriteLine("Listening on " + address);
return server;
}
static void Main(string[] args)
{
// Create and open our host
HttpSelfHostServer server = CreateHost("http://localhost:8080");
Console.WriteLine("Hit ENTER to exit...");
Console.ReadLine();
}
}
public class CustomAssembliesResolver : DefaultAssembliesResolver
{
public override ICollection<Assembly> GetAssemblies()
{
ICollection<Assembly> baseAssemblies = base.GetAssemblies();
List<Assembly> assemblies = new List<Assembly>(baseAssemblies);
var controllersAssembly = Assembly.LoadFrom(#"C:\libs\controllers\ControllersLibrary.dll");
baseAssemblies.Add(controllersAssembly);
return assemblies;
}
}

handle some errors in Global.asax

I have a web application on .NET4 and MVC3 (razor) .
I want to handle my application errors in Global.asax. I have created application_error function.
I have noticed and found some errors.
one of them returns this string in Application_Error when I am trying to add break point on line Response.Clear(); and that error is generic.
how can I find which codes or part of my codes makes it?
my code:
protected void Application_Error()
{
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.Clear();
Server.ClearError();
}
error on httpException:
{System.Web.HttpException (0x80004005): File does not exist.
at System.Web.StaticFileHandler.GetFileInfo(String virtualPathWithPathInfo, String
physicalPath, HttpResponse response)
at System.Web.StaticFileHandler.ProcessRequestInternal(HttpContext context, String
overrideVirtualPath)
at System.Web.DefaultHttpHandler.BeginProcessRequest(HttpContext context,
AsyncCallback callback, Object state) at
System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionSt
ep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean&
completedSynchronously)}
i found the solution
string errorLocation = Request.Path;
this syntax in Application_Error() tel you where is the problem :)
Just to state my experience with this exception, in my case the reason was that there was no webpage specified as the start page for the site.

ASP.NET MVC Routing - differences in web site vs virtual directory

I have an ASP.NET MVC 3 application (in IIS 7.5) with a portable area. When I host the application consuming the portable area in a web site my routing works perfectly e.g.
http://localhost:9001/Clearance/Home/Search (this works)
However, when hosting in a virtual directory e.g.
http://localhost/Acme.Risks.Clearance.Web.Area.TestUI/Clearance/Home/Search (this does not work)
I get the following error:
Multiple types were found that match the controller named 'Home'. This can happen if the route that services this request ('Clearance/{controller}/{action}') does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.
I don't understand why, I am specifying namespaces it works fine when running in a web site.
Here is my portable area registration:
public override void RegisterArea(AreaRegistrationContext context, IApplicationBus bus)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
base.RegisterArea(context, bus);
context.MapRoute(
RouteName.ClearanceAreaDefault,
this.AreaName + "/{controller}/{action}/{id}",
new { controller = "Home", action = "Search", id = UrlParameter.Optional },
new[] { typeof(HomeController).Namespace });
}
Here is the Global.asax for the web application in a virtual directory (does not work):
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { typeof(HomeController).Namespace });
}
Here is the Global.asax for the web application in a web site (does work):
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "Acme.Risks.Web.UI.Controllers" });
}
I have used Phil Haack's "RouteDebugger" (http://nuget.org/packages/routedebugger) and the route debug information on both requests is identical.
Does anyone know why this is happening?
Thanks,
Callum
This was down to the namespace used in the data context for MVC.
My web area assembly is "Acme.Risks.Clearance.Web.Area".
My web site assembly is "Acme.Risks.Web.UI" (working).
My web area test UI assembly is "Acme.Risks.Clearance.Web.Area.TestUI" (not working).
The namespace used in the data context was "Acme.Risks.Clearance.Web.Area*", so in the case of the web area test UI the wildcard caused two matches. So even though the routing information was identical, ASP.NET MVC could not decide which was the right assembly because there were duplicate matches.

Configuring IIS 6.0 to run an MVC3 application

Configuring IIS 6.0 to run an MVC3 application
I think I have a configuration issue on my IIS 6 server and I'd like to see if there's anything I've missed.
The problem that I'm having is that anytime when a RedirectToAction("Index", "Home") is executed (e.g. in a method that returns an ActionResult) I would expect that I would be returned to:
http://servername.domain.com/virtualdirectoryname
However, instead I get redirected to:
http://servername.domain.com/virtualdirectoryname/virtualdirectoryname
That is a second instance of the virtualdirectoryname appended to the end of the URL and can't figure out why - this URL will of course yield a 404 resource not found error. I written and deployed several MVC3 applications both in corporate intranet and public internet environments and can't figure out what I've done wrong. My global.asax.cs seems ok -
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
if (HttpContext.Current.User != null)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
if (HttpContext.Current.User.Identity is FormsIdentity)
{
FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
// Get the stored user-data, in this case, our roles
string userData = ticket.UserData;
string[] roles = userData.Split(',');
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(id, roles);
}
}
}
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
The Application_AuthenticateRequest handles the storing of the roles for logged on users, but other than that, it seems pretty vanilla. The only think I can think of is that I've somehow messed up the virtual directory.
Prior to performing any of these steps, I had verified that MVC3 and v4.0 of the .NET framework were installed on the server. There are also other ASP.NET 4.0 applications on this server that have been running without incident. There is also an MVC2 application (MVC2 is also installed) running on this server and has been running without incident.
I created a virtual directory off of the main "default site" using the IIS manager.
Setup appropriate permissions on the folder that this virtual directory points to. Tested with a quick "Hello, World" index.html file.
Copied the application from my development PC where the application works as developed to the folder described in #2.
Updated the Web.Config file, editing the connection strings to point to the test database server; I had also verified these connection strings on my development PC.
Open the web browser and hope for the best.
Any assistance is greatly appreciated.
Thanks!
I think what you may be seeing is:
http://servername.domain.com/virtualdirectoryname/applicationname
If you have named your virtual directory the same name as your application then I could see how that could confuse you. If you had no virtual directory and just your application at the root of the Default Web Site you'd be seeing:
http://servername.domain.com/applicationname
Is your virtual directory the same name as your application name? If so, that is why you see this.

Resources