How to create URL for Logout action in WebApi - asp.net-mvc

I am using Visual Studio 2017..... when I created the project, an AccountController was created with this action:
// POST api/Account/Logout
[Route("Logout")]
public IHttpActionResult Logout()
{
Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
return Ok();
}
On the other hand, this route was created by default:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
I need to do a very simple thing. How can I get the Logout URL in a view?
I tried
#Url.Action("Logout", "Account", new { httproute = "DefaultApi" })
But it did not work since DefaultApi does not contain the action, causing the action to be added as a query string parameter.
If I don't use httproute property, the URL is built but without the "api" part causing the framework to not find it.
I have even tried
#Url.RouteUrl("DefaultApi", new { httproute = "Logout", controller = "Account" })">
with no success either.

You can define a new route to define your action name:
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
If you don't include the action name, Web API tries to find a suitable action for you based on your HTTP verb... for example if you send a Get request Web API tries to find an action starting with 'Get'... since your action name is Logout, the default API routing convention cannot match it to a request. see here for more info
Then this link should call the action (see here):
#Url.HttpRouteUrl("ActionApi", new {controller = "Account", action = "Logout"})

Related

Dealing with multiple GET actions Web API

I am new to WEB API and trying to set up routing for multiple GET actions.
Controller Code
// Get api/values
public IEnumerable<tblUser> Get()
{
//whatever
}
// Get api/values/action
[ActionName("GetByQue")]
public IEnumerable<tblQue> GetQue()
{
//whatever
}
// Get api/values/action
[ActionName("GetUserScore")]
public IEnumerable<tblScore> GetScore(string user)
{
//whatever
}
Config
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional}
);
config.Routes.MapHttpRoute(
name: "DefaultActionApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { action = "GetByQue" }
);
config.Routes.MapHttpRoute(
name: "DefaultStringApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { action = "GetUserScore" }
);
When I try with http://localhost:54118/api/remote/GetByQue URL getting this error
{
"Message": "The request is invalid.",
"MessageDetail": "The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.String Get(Int32)' in 'HydTechiesApi.Controllers.HydTechiesApiController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."
}
is my routing wrong? Any help would be valuable as I am not able to find a solution.
You should add {action} to routeTemplate instead of {id} in the second configuration
config.Routes.MapHttpRoute(
name: "DefaultActionApi",
routeTemplate: "api/{controller}/{action}",
defaults: new { action = "GetByQue" }
);
also you can try to use route attribure on action :
[ActionName("GetByQue")]
[Route("api/remote/GetByQue")]
public IEnumerable<tblQue> GetQue()
{
//whatever
}
or change order(the second configuration and first configuration) of configuration in WebApiConfig.cs
You made a couple of mistakes in your route. As your example code below:
config.Routes.MapHttpRoute(
name: "DefaultActionApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { action = "GetByQue" });
//url: http://localhost:54118/api/remote/GetByQue
(1). routeTemplate: "api/{controller}/{id}". you specify your route has an id and it is not Optional. So your URL must have id. That's what your error showed.you can handle with the issue like below:
defaults: new { id = RouteParameter.Optional }
(2). defaults: new { action = "GetByQue" }); you did not say any thing about action in your routeTemplate. your defaults about action, which does not have any meaning.
(3). From your route, your URL should look like http://localhost:54118/api/remote/5 , you should not get mutiple get method by your route.
There are some solutions, which you may use:
(1). change route like below:
config.Routes.MapHttpRoute(
name: "DefaultActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
please add [HttpGet] in each method just in cause.
[HttpGet]
public IEnumerable<tblUser> Get()
{......}
[HttpGet]
[ActionName("GetByQue")]
public IEnumerable<tblQue> GetQue()
{......}
[HttpGet]
[ActionName("GetUserScore")]
public IEnumerable<tblScore> GetScore(string user)
{......}
Now you can use URL like http://localhost:54118/api/remote/GetByQue
Very Useful Tips: Using [Route("")] tag to specify parameters
**You also have to change Route like above (1)
in Controller, please specify request method to make sure the get method
[HttpGet]
[ActionName("GetUserScore")]
[Route("api/remote/GetScore/{user}")]
public IEnumerable<tblScore> GetScore(string user)
{.....}
//URL: http://localhost:54118/api/remote/GetScore/user

Telerik reports without trdx files

I am banging my head against the brick to get this working. I have reports which are generated using report designer and they are working fine as i have loaded them using an iframe now i want to use Html5 report viewer. But in most of the tutorials out there they are using trdx reports rather than one being generated using report Designer.
I have a class library named XYZ.TelerikReports where all the reportname.cs (reports ) files resides and i have my main project in the same solution where i want to show the reports.
$("#reportViewer1")
.telerik_ReportViewer({
serviceUrl: "/api/reports/",
templateUrl: '/ReportViewer/templates/telerikReportViewerTemplate.html',
reportSource: {
report: "XYZ.TelerikReports.IncomeStatementReport,XYZ.TelerikReports"
parameters: { ReportDataID: parseInt('#state.CurrentReportDataID') }
},
scale: "1.0"
});
Now i am wondering what should be my serviceUrl ?
The serviceUrl expects to be routed to the Telerik Reporting Web API controller. The current value you use /api/reports/ is Telerik's default name for this controller. The documentation details how to implement the Web API controller pretty well. You'll find that here http://www.telerik.com/help/reporting/telerik-reporting-rest-host-http-service-using-web-hosting.html and here http://www.telerik.com/help/reporting/telerik-reporting-rest-implementing-http-service.html.
This controller will resolve the requested report successfully if the report name is that of a report class or a .trdx. Alternatively you can implement a customer report resolver. This can be done by following the instructions in the documentation here http://www.telerik.com/help/reporting/telerik-reporting-rest-custom-report-resolver.html.
So your serviceUrl is fine. You just need to make sure that you have the service it calls setup.
One possible Approach is to modify your reporting API controller to use the report type resolver and alter the CreateReportResolver e.g.
protected override IReportResolver CreateReportResolver()
{
var reportsPath = HttpContext.Current.Server.MapPath("~/Reports");
return new ReportTypeResolver()
.AddFallbackResolver(new ReportFileResolver(reportsPath));
}
Then specify the Fully Qualified Assembly name or classname of each report in the HTML5 Viewer Configuration (as you are already doing).
With regards to the path for the service url, you can use the api/reports route you have above, but you must call the telerik reporting route registration function in your WebApiConfig.Register function, i.e.:
ReportsControllerConfiguration.RegisterRoutes(GlobalConfiguration.Configuration);
This means your reporting api is inside a controller called ReportsController.
Alternatively, you can customize the path to something like /Controllers/MyCustomReports by implementing your own reporting routes registration function and calling it instead of the above snippet. For instance, you can have:
private static void RegisterReportingRoutes(HttpConfiguration config)
{
config.Routes.MapHttpRoute(name: "Clients",
routeTemplate: "Controllers/{controller}/clients/{clientID}",
defaults: new { controller = "MyCustomReports", action = "Clients", clientID = RouteParameter.Optional });
config.Routes.MapHttpRoute(
name: "Instances",
routeTemplate: "Controllers/{controller}/clients/{clientID}/instances/{instanceID}",
defaults: new { controller = "MyCustomReports", action = "Instances", instanceID = RouteParameter.Optional });
config.Routes.MapHttpRoute(
name: "DocumentResources",
routeTemplate: "Controllers/{controller}/clients/{clientID}/instances/{instanceID}/documents/{documentID}/resources/{resourceID}",
defaults: new { controller = "MyCustomReports", action = "DocumentResources" });
config.Routes.MapHttpRoute(
name: "DocumentActions",
routeTemplate: "Controllers/{controller}/clients/{clientID}/instances/{instanceID}/documents/{documentID}/actions/{actionID}",
defaults: new { controller = "MyCustomReports", action = "DocumentActions" });
config.Routes.MapHttpRoute(
name: "DocumentPages",
routeTemplate: "Controllers/{controller}/clients/{clientID}/instances/{instanceID}/documents/{documentID}/pages/{pageNumber}",
defaults: new { controller = "MyCustomReports", action = "DocumentPages" });
config.Routes.MapHttpRoute(
name: "DocumentInfo",
routeTemplate: "Controllers/{controller}/clients/{clientID}/instances/{instanceID}/documents/{documentID}/info",
defaults: new { controller = "MyCustomReports", action = "DocumentInfo" });
config.Routes.MapHttpRoute(
name: "Documents",
routeTemplate: "Controllers/{controller}/clients/{clientID}/instances/{instanceID}/documents/{documentID}",
defaults: new { controller = "MyCustomReports", action = "Documents", documentID = RouteParameter.Optional });
config.Routes.MapHttpRoute(
name: "Parameters",
routeTemplate: "Controllers/{controller}/clients/{clientID}/parameters",
defaults: new { controller = "MyCustomReports", action = "Parameters" });
config.Routes.MapHttpRoute(
name: "Formats",
routeTemplate: "Controllers/{controller}/clients/{clientID}/formats",
defaults: new { controller = "MyCustomReports", action = "Formats" });
}
Note that you should reference the reports library from the solution containing the REST services.

How do I generate a webapi url from an MVC view?

Based on How to create ASP.NET Web API Url?
Neither of these plus a few more combinations of them I've tried are working
<li>CorpUser</li>
<li>CorpUser</li>
Here's my api config route table:
//https://stackoverflow.com/questions/11407267/multiple-httppost-method-in-mvc4-web-api-controller
config.Routes.MapHttpRoute(
name: "ApiReq",
routeTemplate: "webapi/{controller}/{action}",
defaults: null,
constraints: new { action = "Req" }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new
{
id = #"^\d*$",// Only integers
action = "^(?![rR]eq)$" //anything except req or Req
}
);
Why isn't the routing working? The RouteUrl returns empty string or null, the Action returns
<a href="http://localhost:11601/CorpUserRequest/Get">
instead of what the actual url should be http://localhost:11601/api/CorpUserRequest
You could use either of the following to generate links to Web API:
#Url.HttpRouteUrl("DefaultApi", new {controller = "corpuserrequest"})
#Url.RouteUrl("DefaultApi", new { httproute = true, controller = "corpuserrequest"})
Usually you would use option 1., but sometimes you might need to use 2. like in the following post (this post doesn't necessarily use RouteUrl, but the idea is that in places where you do not have a convenient extension like HttpRouteUrl, in this case Html.BeginForm, you can use httproute=true to indicate that you are indeed trying to generate a url to a Web API route)
ASP.Net WebApi: Invalid URL generated in BeginForm

ASP.NET Web API Routing in ApiController

I've been struggling with my routing for some time now and after a few days of trying to Google the solution without luck, I'm hoping someone may be able to shine some light on my problem.
I have the following routes in my WebApiConfig:
config.Routes.MapHttpRoute(
name: "AccountStuffId",
routeTemplate: "api/Account/{action}/{Id}",
defaults: new { controller = "Account", Id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "AccountStuffAlias",
routeTemplate: "api/Account/{action}/{Alias}",
defaults: new { controller = "Account", Alias = RouteParameter.Optional }
);
and the following controller methods:
[HttpGet]
public Account GetAccountById(string Id)
{
return null;
}
[HttpGet]
public Account GetAccountByAlias(string alias)
{
return null;
}
If I call:
/API/Account/GetAccountById/stuff then it properly calls GetAccountById.
But if I call /API/Account/GetAccountByAlias/stuff then nothing happens.
Clearly order matters here because if I switch my declarations of my routes in my WebApiConfig, then /API/Account/GetAccountByAlias/stuff properly calls GetAccountByAlias, and /API/Account/GetAccountById/stuff does nothing.
The two [HttpGet] decorations are part of what I found on Google, but they don't seem to resolve the issue.
Any thoughts? Am I doing anything obviously wrong?
Edit:
When the route fails, the page displays the following:
<Error>
<Message>
No HTTP resource was found that matches the request URI 'http://localhost:6221/API/Account/GetAccountByAlias/stuff'.
</Message>
<MessageDetail>
No action was found on the controller 'Account' that matches the request.
</MessageDetail>
</Error>
You should be able to just have the following route:
config.Routes.MapHttpRoute(
name: "AccountStuffId",
routeTemplate: "api/Account/{action}/{Id}",
defaults: new { controller = "Account", Id = RouteParameter.Optional }
);
and do the following for your actions:
[HttpGet]
public Account GetAccountById(string Id)
{
return null;
}
[HttpGet]
public Account GetAccountByAlias([FromUri(Name="id")]string alias)
{
return null;
}
Is there a reason you need to be declaring two different routes?
Look at the guide at: http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api
They have one default route and going by the example all you need in your config is
routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

MVC 4 Web API Routing issues

This is my first rodeo with MVC Web API and I'm having some issues understanding the routing aspects. I would like to have a uri template similar to thise:
http://google.com/api/AzureQueue - GET for all items in the queue
http://google.com/api/AzureQueue/DeviceChart/ - GET returns devices and processing time for agent
http://google.com/api/{controller}/{id} <-- default
http://google.com/api/{controller}/{chartType}/{id} where ID is optional
where I'm struggling is:
1. what the french toash do I put in the WebApiConfig.cs file
2. do I need to do anthing special in my controller eg. specifiy NonActions & Actions, Action Names, etc
Any help is appreciated
You are almost there. The default route (in WebApiConfig.cs looks like this:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
There's one very important caveat: the routes are examined in the order that they are declared with the first matching one being used, so the default route needs to go last.
With that out of the way, you need to make a decision, do you want the calls for various chart types to go to one action, or many?
For one action:
WebApiConfig.cs
config.Routes.MapHttpRoute(
name: "AzureQueue",
routeTemplate: "api/AzureQueue/{chartType}/{id}",
defaults: new { controller = "AzureQueue", id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
AzureQueueController.cs
public class AzureQueueController : ApiController
{
public string Get(string chartType)
{
return "chart = " + chartType;
}
public string Get(string chartType, int id)
{
return "chart = " + chartType + ",id = " + id.ToString();
}
}
There are two things to notice here. In the anonymous class assigned to defaults, the value for controller decides which controller to route the request to. This can either be in the route template, or simply defined in the class. Also, a request of type Get is automatically sent to an action that starts with Get and has the arguments in the Url that match the template (there are two different cases since id is optional).
This would be my preferred way to go unless the business logic for various charts is different.
On the other hand you could specify this:
WebApiConfig.cs
config.Routes.MapHttpRoute(
name: "AzureQueue",
routeTemplate: "api/AzureQueue/{action}/{id}",
defaults: new { controller = "AzureQueue", id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Since I'm using the word action is the template, this will get interpreted as an action name.
AzureQueueController.cs
[HttpGet]
public string DeviceChart()
{
return "chart = DeviceChart" ;
}
[HttpGet]
public string DeviceChart(int id)
{
return "chart = DeviceChart" + ",id = " + id.ToString();
}
Here there is no string argument, that part of the url is being used to decide which action (public method) to use. Also, since the action names don't start with Get, I need to add an attribute [HttpGet] for each method to mark them as being able to receive GET requests.
Good luck with your project.

Resources