Need help.
I have 2 controllers:
// POST (Single SMS)
[ActionName("AddSMS")]
public HttpResponseMessage Post(MySMS singleSMS)
{
try
{
SMS_Repository.Add(singleSMS);
return Request.CreateResponse<MySMS>(HttpStatusCode.Created, singleSMS);
}
catch (Exception)
{
return Request.CreateErrorResponse(HttpStatusCode.ExpectationFailed, "Error");
}
}
// POST (Collection of SMSes)
[ActionName("AddSMSCollection")]
public HttpResponseMessage Post(List<MySMS> smses)
{
try
{
SMS_Repository.Add(smses);
return Request.CreateResponse<List<MySMS>>(HttpStatusCode.Created, smses);
}
catch (Exception)
{
return Request.CreateErrorResponse(HttpStatusCode.ExpectationFailed, "errorus");
}
}
and Route:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional, action = RouteParameter.Optional }
Now. If I send request like this:
localhost:25856/api/sms/AddSMSCollection
it works
Is it possible to tune route so that I can use localhost:25856/api/sms and didn't get Multiple actions were found that match the request error??
sorry for my bad english..
You could define the action that should be executed in this case:
defaults: new { id = RouteParameter.Optional, action = "AddSMS" }
But with only the following url localhost:25856/api/sms and not including the action name, I hope you realize that the routing engine has no way of disambiguate which action to execute. The routing engine could use the HTTP verb but in your case both actions are POST.
Related
I have trouble to hit webapi action.
I am getting 500 error in the console and the api is not reached.
This is my ajax call:
function getProducts() {
var response;
$.getJSON("/api/Product")
.done(function (data) {
response = $.map(data,
function (item) {
return { label: item.Name + ' (' + item.Code + ')' };
});
});
return response;
};
The ajax is not hitting. The request skips getJson call and returns undefined response.
This is my api controller method:
public class ProductController : ApiController {
// GET api/<controller>
public IEnumerable<ProductModel> ProductList()
{
ProductSearcher searcher = new ProductSearcher();
return searcher.GetResults();
}
}
In the config I have defined:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Postman returns Object reference not set to an instance of an object but it doesn't even hit the ProductList either.
I have selected to run multiple projects - my app start project and web api project.
This is the error stacktrace - it looks to me like umbraco does looks for routing while I need to route to non-umbraco api:
[NullReferenceException: Object reference not set to an instance of an object.]
Umbraco.Web.Routing.ContentLastChanceFinderByNotFoundHandlers.HandlePageNotFound(PublishedContentRequest docRequest) +152
Umbraco.Web.Routing.ContentLastChanceFinderByNotFoundHandlers.TryFindContent(PublishedContentRequest docRequest) +10
Umbraco.Web.Routing.PublishedContentRequestEngine.HandlePublishedContent() +529
Umbraco.Web.Routing.PublishedContentRequestEngine.FindPublishedContentAndTemplate() +250
Umbraco.Web.Routing.PublishedContentRequestEngine.PrepareRequest() +107
Umbraco.Web.UmbracoModule.ProcessRequest(HttpContextBase httpContext) +361
Umbraco.Web.UmbracoModule.<Init>b__8(Object sender, EventArgs e) +80
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +141
System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +48
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +71
EDIT
I changed the routing config from api to dataapi eg. routeTemplate: "dataapi/{controller}/{id}" so it now runs but still throws an error:
405 Method not allowed
EDIT 2
Got it! Changed the method name from ProductList to Get and it's now working
You could use an UmbracoApiController instead, to make sure that Umbraco doesn't try to match the URLs to content? Then the path to the controller would be /umbraco/api/yourcontroller instead, but everything should work the same. Take a look at https://our.umbraco.com/documentation/reference/routing/webapi/ for details.
Alright, I'm having a tough time locating the problem since it works locally but after doing a publish the results are simply:
Error Code: 403 Forbidden. The server denied the specified Uniform Resource Locator (URL). Contact the server administrator. (12202)
The code:
[RoutePrefix("api/v1/project")]
public class ProjectController : BaseApiController
{
[HttpGet]
public HttpResponseMessage GetProjects()
{
HttpResponseMessage resp = new HttpResponseMessage(HttpStatusCode.OK);
if(User.Identity.IsAuthenticated)
{
var model = new ModelFactory().CreateProjects();
resp = Request.CreateResponse(HttpStatusCode.OK, model);
}
return resp;
}
}
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// all actions under /project routes require authentication
config.Routes.MapHttpRoute(
name: "ProjectApi",
routeTemplate: "api/v1/{controller}/{action}/{apikey}",
defaults: new { apikey = RouteParameter.Optional },
constraints: new { controller = "project" },
handler: new BasicAuthHandler(config));
// all routes requires an api key
config.MessageHandlers.Add(new ApiKeyHandler());
config.MapHttpAttributeRoutes();
}
}
I've tried several "solutions" from the net yet none of them seems to fix this. I've added the:
// Stop IIS/Asp.Net breaking our routes
RouteTable.Routes.RouteExistingFiles = true;
from: http://www.grumpydev.com/2013/09/17/403-14-error-when-trying-to-access-a-webapi-route/
And also made sure that:
<modules runAllManagedModulesForAllRequests="true">
Having the code above, using the following link gives a successful connection where it checks (in the correct order) the APIkey (ApiKeyHandler), checks if the user needs to log in(BasicAuthHandler) and then goes to method in the controller ({controller}/{action}).
// THIS WORKS!
http://localhost:51077/api/v1/project/getprojects?apikey=123456
then we do a publish and tries the same thing
// This is haunted with number 403
http://website.com/api/v1/project/getprojects?apikey=123456
gives the Error Code: 403 Forbidden.
I am clueless. I've even tried changing the whole publish folder's security settings for "NETWORK SERVICE" to full access.. no change.
Let me know if you need any more intel.
Called the web server machine fellas and they had a firewall blocking incoming webapi calls with authenticating. It now works as it should :)
I just applied Update 2 RTM to Visual Studio 2013 and started a new Web API project. I have a basic service returning some people objects.
I'm trying to use content negotiation to return JSON or XML depending on the Accept header. Regardless of the Accept header, I get JSON. How do I troubleshoot this and return XML or JSON depending on the header?
Here is the Header from Fiddler: Accept: application/xml
Here is the body of my Get() method:
var patient = this.patientRepository.GetPatients().Where(p => p.Identifier == id).FirstOrDefault();
IContentNegotiator negotiator = this.Configuration.Services.GetContentNegotiator();
ContentNegotiationResult result = negotiator.Negotiate(typeof(Patient), this.Request, this.Configuration.Formatters);
if (result == null)
{
var response = new HttpResponseMessage(HttpStatusCode.NotAcceptable);
throw new HttpResponseException(response);
}
return new HttpResponseMessage()
{
Content = new ObjectContent<Patient>(patient, result.Formatter, result.MediaType.MediaType)
};
Thanks!
Update - Here is the WebApiConfig.cs. I added the line adding the XmlMediaTypeFormatter. By default, it's not included. Either way, the issue is not resolved.
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
GlobalConfiguration.Configuration.Formatters.Add(new XmlMediaTypeFormatter());
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
I have the following function in a PersonController class
[HttpGet]
[ActionName("GetBloggersNotFollowed")]
public IQueryable<object> GetBloggersNotFollowed(int companyId)
{
return Uow.People.GetPeople().Select(p => new { p.Email, p.FirstName, p.LastName, p.PhoneNumber, p.Type, p.UserName, p.Country, p.Id });
}
It is used to retrieve a list of people.
I call the function as so
$.ajax({
url: "/api/person/GetBloggersNotFollowed/1"
}).success(function (people) {
PersonModule.GetPeople(people);
});
And i have declared a route in my WebApiConfig.cs
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
When I try to call the route in the browser i get an error
<Error>
<Message>
No HTTP resource was found that matches the request URI 'http://localhost:1045/api/person/GetBloggersNotFollowed/1'.
</Message>
<MessageDetail>
No action was found on the controller 'Person' that matches the request.
</MessageDetail>
</Error>
I don't know here I went wrong. Can anyone see the problem?
The name of the parameter is important to the route matching.
You have named the parameter id in the route yet the method has it as companyId.
Either change {id} in the route to {companyId} or change companyId parameter to id.
Replace your your route to this one:
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{companyId}",
defaults: new { id = RouteParameter.Optional }
);
This answer complements Mark Jones' answer.
I have the following set-up in my config:
routes.MapHttpRoute("NoAuthRequiredApi", "api/auth/", new { id = RouteParameter.Optional } );
routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional }, null, new WebApiAuthenticationHandler());
If I post anything to the url on api/auth the message handler still runs and checks for an Auth-Token header. Is there any reason why this is happening? Is there something I should change in the configuration of the WebApi routes? I obviously don't want any auth token on the header when making requests to the auth controller because at that point I'm trying to retrieve the token for use on other controllers.
Your topmost route is never being matched as there is no indication of which controller is required. Add the controller name in as a default. (And remove the ID optional if this is not required).
So:
routes.MapHttpRoute(
name: "NoAuthRequiredApi",
routeTemplate: "api/auth/",
defaults: new { Controller = "Auth" }
);