I am trying to generate a url from within one of my web api actions:
var resultsModel =
results.Select(
r =>
new ResultModel(criteria,
r,
Url.Link("Default", new { Controller = "CV", Action = "Get", candidateid = r.CandidateId, filename = r.Name })
, false))
.ToList();
however the genrated url is missing the "api/" prepender and therefor does not work as the url cannot be resolved.
https://temp-search.recruiter.workstation.local/recruiter/temp-search/cv/get?candidateid=14350164&filename=Douggersby%20Mondays&id=143501
the following is my web api config:
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new AuthorizationHandler());
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
You're referring to the 'Default' route instead of the 'DefaultApi' route.
Instead of:
Url.Link("Default", new { Controller = "CV", Action = "Get", candidateid = r.CandidateId, filename = r.Name })
, false))
Use:
Url.Link("DefaultApi", new { Controller = "CV", Action = "Get", candidateid = r.CandidateId, filename = r.Name })
, false))
And the 'DefaultApi' route template will be used to generate the url, including the api/ prefix.
Related
I am working with WebApi and trying to add token based authentication using OWIN. It is working fine when client and service are in the same port. But facing a problem when both are on different servers.
I am using Jquery Ajax method to call the token service.
Here is the code sample I have used.
OWIN Code :
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
ConfigureOAuth(app);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/WagtokenService"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new ProjectAuthorizationServiceProvider()
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
Provider
public class ProjectAuthorizationServiceProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");
if (allowedOrigin == null) allowedOrigin = "*";
bool isValidUser = false;
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
if (context.UserName == "Test#Mail.com" && context.Password == "national")
{
isValidUser = true;
}
if (!isValidUser)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "admin"));
context.Validated(identity);
}
}
WebApi Config
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("http://192.168.2.175:3330", "WagtokenService,accept,accesstoken,authorization,cache-control,pragma,content-type,origin", "GET,PUT,POST,DELETE,TRACE,HEAD,OPTIONS");
config.EnableCors(cors);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "NewActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Following code snippet will be called when login button is clicked.
$('#a_login').click(function (e) {
debugger;
if (isValidEmailAddress($('#txt_UID').val()) && $('#txt_PWD').val() != "") {
var loginData = {
grant_type: 'password',
username: $('#txt_UID').val(),
password: $('#txt_PWD').val()
};
$.ajax({
url: url_bearerToken,
type: 'POST',
data: loginData,
contentType: "application/json",
done: function (data) {
// alert('success fully sign in to the application');
sessionStorage.setItem(bearer_token_key, data.access_token);
},
success: function (data) {
// alert('success fully sign in to the application');
sessionStorage.setItem(bearer_token_key, data.access_token);
window.location.href = "../Admin/UserProfiler.html";
},
error: function (x, h, r) {
///e.preventDefault();
// alert("Invalid user credentials");
$('#div_alert').show();
sessionStorage.setItem(bearer_token_key, '');
}
});
}
else {
$('#div_alert').show();
}
});
Getting Following issue .
XMLHttpRequest cannot load http://localhost:53014/WagtokenService. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://192.168.2.175:3330' is therefore not allowed access.
As Marcus said , it is enough to mention CORS setting either in Web API or in OWIN.
I have added two GET methods into webapi as follow:
public IList<ProductDTO> GetAllProducts()
{
ProductManager pm = new ProductManager();
return pm.RetrieveAllProducts();
//return pm.RetrieveAllProducts();
}
public ProductDTO GetProduct(int i)
{
ProductManager pm = new ProductManager();
return pm.RetrieveAllProducts().Where(c => c.Id == i).FirstOrDefault();
//return pm.RetrieveAllProducts();
}
Problem, when i only kept one get method GetAllProducts() then it works fine. but when i added GetProduct(int i) then giving me error as Not found 404 error.
Please guide me how i could keep both the mthod and allow to access method having argument.
calling as follow:
$.ajax({
type: 'GET',
url: 'api/values/GetProduct/1', //giving error as NOT FOUND
contentType: 'json',
dataType: 'json',
success: function (data) {
$.each(data, function (key, value) {
//stringify
alert(key);
alert(value);
var jsonData = JSON.stringify(value);
//Parse JSON
var objData = $.parseJSON(jsonData);
var id = objData.Id;
var Cost = objData.Cost;
var ProductName = objData.ProductName;
var Description = objData.Description;
$('<tr><td>' + id + '</td><td>' + ProductName +
'</td><td>' + Cost + '</td></tr>').appendTo('#ProductDivWebApi');
});
},
error: function (xhr) {
alert(xhr.responseText);
}
});
i have added this WEBAPI into MVC 4 project.
its route shows as below:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "ProductManagement", action = "Index", id = UrlParameter.Optional }
);
}
Please guide
The routes on the ASP.NET WEB API is different than ASP.NET MVC. You have the GET methods, so, just call the controller using the GET verb and the framework will solve it for you. I recommend you rename the methods to a verb, Get, Post, Put, Delete, etc.
In your case, call the method by /api/{controller}/{id}. In this case, data is a single object (because you have returned only a ProductDTO), so do not loop in it.
You have specified json, so jquery will be deserialized it in a object for you. For sample:
$.ajax({
type: 'GET',
url: 'api/values/1',
contentType: 'json',
dataType: 'json',
success: function (data) {
// data is a single object, do not loop in it.
// you have specified json, so, it will be deserialized
var id = data.Id;
var Cost = data.Cost;
var ProductName = data.ProductName;
var Description = data.Description;
$('<tr><td>' + id + '</td><td>' + ProductName +
'</td><td>' + Cost + '</td></tr>').appendTo('#ProductDivWebApi');
});
},
error: function (xhr) {
alert(xhr.responseText);
}
});
I also recommend you to do some things like this on Web API:
[HttpGet]
public HttpResponseMessage GetProduct(int id)
{
ProductManager pm = new ProductManager();
var result = pm.RetrieveAllProducts().Where(c => c.Id == id).FirstOrDefault();
return Request.CreateResponse(HttpStatusCode.OK, result);
}
On the WebApiConfig.cs file I recommend you configure the routes like this:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute("DefaultApiGet",
"api/{controller}",
new {action = "Get"},
new {httpMethod = new HttpMethodConstraint(HttpMethod.Get)});
config.Routes.MapHttpRoute("DefaultApiGetWithId",
"api/{controller}/{id}",
new {id = RouteParameter.Optional, action = "Get"},
new {id = #"\d+"});
config.Routes.MapHttpRoute("DefaultApiWithAction",
"api/{controller}/{action}");
config.Routes.MapHttpRoute("DefaultApiWithActionAndId",
"api/{controller}/{action}/{id}",
new {id = RouteParameter.Optional},
new {id = #"\d+(_\d+)?"});
}
Below is my web api stuff related post/save the record:
var c = $.ajax({
url: 'api/values/CreateAjaxNew',
type: 'POST',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: form.serializeArray(),
success: function (data) {
alert(data);
$("#msg").html("Saved Successfully.");
$("#msg").css("color", "green");
//window.location = "index";
//alert("in success");
},
error: function (e1, e2, e3) { alert(e3); }
});
Problem: it just gieves me error as Not Found.
Values controller api:
[HttpPost]
public HttpResponseMessage CreateAjaxNew(ProductViewModel vm)
{
try
{
// TODO: Add insert logic here
//manager.ProductManager m = new manager.ProductManager();
using (aRef.ServiceIntf2Client r = new aRef.ServiceIntf2Client())
{
r.InsertProduct(new common.DTO.ProductDTO() { Id = vm.Id, ProductName = vm.ProductName, Description = vm.Description, Cost = vm.Cost, ProductTypeId = vm.ProductTypeId });
}
//m.InsertProduct(new common.DTO.ProductDTO() { Id = vm.Id, ProductName = vm.ProductName, Description = vm.Description, Cost = vm.Cost, ProductTypeId = vm.ProductTypeId });
return Request.CreateResponse(HttpStatusCode.OK,true);
}
catch
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, false);
}
}
Please guide me how i can resolve this issue so, request reach to the api action.
routes as follow:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute("DefaultApiGet",
"api/{controller}",
new { action = "AllProductTypes" },
new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) });
config.Routes.MapHttpRoute("DefaultApiGet1",
"api/{controller}",
new { action = "GetAllProducts" },
new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) });
config.Routes.MapHttpRoute("DefaultApiGetWithId",
"api/{controller}/{id}",
new { id = RouteParameter.Optional, action = "Get" },
new { id = #"\d+" });
config.Routes.MapHttpRoute("DefaultApiWithAction",
"api/{controller}/{action}");
config.Routes.MapHttpRoute("DefaultApiWithActionAndId",
"api/{controller}/{action}/{id}",
new { id = RouteParameter.Optional },
new { id = #"\d+(_\d+)?" });
The route ordering seems to be wrong. You need to move the default route to the last and the more generic route first .
http://richarddingwall.name/2008/08/09/three-common-aspnet-mvc-url-routing-issues/
As of now the api/{controller}/{id} the default route get executed and the controller is not found.
config.Routes.MapHttpRoute("DefaultApiGet",
"api/{controller}",
new { action = "AllProductTypes" },
new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) });
config.Routes.MapHttpRoute("DefaultApiGet1",
"api/{controller}",
new { action = "GetAllProducts" },
new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) });
config.Routes.MapHttpRoute("DefaultApiGetWithId",
"api/{controller}/{id}",
new { id = RouteParameter.Optional, action = "Get" },
new { id = #"\d+" });
config.Routes.MapHttpRoute("DefaultApiWithAction",
"api/{controller}/{action}");
config.Routes.MapHttpRoute("DefaultApiWithActionAndId",
"api/{controller}/{action}/{id}",
new { id = RouteParameter.Optional },
new { id = #"\d+(_\d+)?" });
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
This ordering should be able to solve the issue. Hope this helps
I have this global.asax file with this code:
routes.MapRoute("Invitations",
"api/invitations",
new { controller = "Invitations", action = "Invitation"});
And I have a Controller:
public class InvitationsController : Controller
{
[HttpPut]
public JsonResult Invitation(InvitationResponse invitationResponse)
{
//code
}
}
And I'm accessing the controllers by HttpWebRequest with this URL:
"http://localhost:6055/API/Invitations"
When I run this I get the error "NotFound".
EDIT:
The whole global route:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("Users",
"api/users/{id}",
new { controller = "Users", action = "UserAction", id = UrlParameter.Optional });
routes.MapRoute("CheckIn",
"api/checkins",
new { controller = "CheckIn", action = "CheckIn" });
routes.MapRoute("Appointments",
"api/appointments/{id}",
new { controller = "Appointments", action = "Appointment", id = UrlParameter.Optional });
routes.MapRoute("UserAppointments",
"api/users/{userId}/appointments/{startDate}",
new { controller = "Appointments", action = "UserAppointments", startDate = UrlParameter.Optional });
routes.MapRoute("UserInvitations",
"api/users/{userId}/invitations",
new { controller = "Invitations", action = "UserInvitations" });
routes.MapRoute("UserOverview",
"api/users/{id}/overview",
new { controller = "Users", action = "Overview" });
routes.MapRoute("Invitations",
"api/invitations",
new { controller = "Invitations", action = "Invitation"});
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
"http://localhost:6055/API/Invitations" doesn't look correct, shouldn't it be
"http://localhost:6055/YourApp/API/Invitations"
I have a module called News as Area. In NewsAreaRegistration I have
context.MapRoute(
"NewsShow",
"News/{controller}/{friendlyUrlName}/{idNews}",
new { controller = "Show", action = "Index", friendlyUrlName = "", idNews = "" }
);
In my view (in main View folder) I use RouteUrl method to enforce my custom route
#Url.RouteUrl("NewsShow", new { controller = "Show", action = "Index", friendlyUrlName = FriendlyURL.URLFriendly(true, Model.News.Data.ElementAt(0).Title), idNews = Model.News.Data.ElementAt(0).IdNews})"
What I would like to do is have a route like this www.something.com/News/Show/bla-bla-bla/9
without action name Index that I have in Show controller. I tried literaly all permutations of this example and nothing worked. Is this even possible?
Ok, so I tried this out....
Routing table: (before default)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapRoute(
name: "Hidden",
url: "News/{controller}/{friendlyUrlName}/{idNews}",
defaults: new {controller = "Home", action = "Index", friendlyUrlName = "", idNews = ""});
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Account", action = "Index", id = UrlParameter.Optional }
);
In the View:
#Url.RouteUrl("Hidden", new { friendlyUrlName = "Dude-Check-It-Out", idNews = 12 })
in my controller:
public ActionResult Index(string friendlyUrlName, int idNews)
{
ViewBag.Message = "Modify this template to kick-start your ASP.NET MVC application.";
ViewBag.UrlName = friendlyUrlName;
ViewBag.NewsId = idNews;
return View();
}
and I got this..
/News/Home/Dude-Check-It-Out/12
URL I go to:
http://localhost:49840/News/Home/Dude-Check-It-Out/12
I also changed my default route to something else to ensure that this wasn't using the default route. Let me know if this helped :)
Did you put this route before default one? Route position is important, from top to bottom.
Ok...I managed to work somehow.
In my NewsAreaRegistration I had to move NewsShow route before default. Not sure why, becuase RouteUrl should map excatly to NewsShow.
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"NewsShow",
"News/{controller}/{friendlyUrlName}/{idNews}",
new { controller = "Show", action = "Index", friendlyUrlName = "", idNews = "" }
);
context.MapRoute(
"News_default",
"News/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
This is my RouteUrl now (notice I had to write controller.Not sure exactly why either:
#Url.RouteUrl(
"NewsShow", new { controller = "Show", friendlyUrlName = FriendlyURL.URLFriendly(true, Model.News.Data.ElementAt(0).Title), idNews = Model.News.Data.ElementAt(0).IdNews }
);