public ActionResult Edit(string param)
{
}
http://localhost/Edit/5,someothervalue,etc
How can i reach 'param' from a global function. Basically I am trying to access the parameter in my url from a statinc method that I am building which will be global. That method breaks down the parameter and returns id and other things that I am passing inside param
I think you're looking for a way to get the route values from a given URL. Here's some code that might help you do this with a URL string. Just note that I put a IRouteRegistrant interface that just has a Register function that takes a route collection. Basically replace that with your registration mechanism.
public static RouteData GetRouteValues(IRouteRegistrant registrant, string url)
{
var routes = new RouteCollection();
registrant.Register(routes);
var context = new FakeHttpContext(url);
return routes.GetRouteData(context);
}
So to get at the values (for your param example) you just need the following:
public static void MyFn()
{
var values = GetRouteValues(....., "~/Edit/5");
var paramValue = values.Values["param"];
.....
}
Hope this helps.
Related
My project is using the following code to generate MVC routed URLs for the given routeName and routeValues:
public class RouteBuilder
{
public string GetUrl(string routeName, object routeValues)
{
return RouteTable.Routes.GetVirtualPath(
new RequestContext(new MockHttpContextBase(string.Empty), new RouteData()),
routeName,
new RouteValueDictionary(routeValues)
)?.VirtualPath;
}
}
For example, given the following route definition:
public MyController : Controller
{
[Route("Foo", "{bar}/{quux}")]
public IActionResult MyControllerMethod(MyModel model) { }
}
we call:
// yields "zod/baz"
var routedUrl = RouteBuilder.GetUrl("Foo", new
{
bar = "zod",
quux = "baz",
});
The problem comes in with the route values object passed to GetUrl. Out of necessity it can be any type of object, including an anonymous one as demonstrated in the example. But this is problematic because if there are any typos in the object's definition, the route template won't match and the URL won't be built:
// yields null!
var routedUrl = RouteBuilder.GetUrl("Foo", new
{
baz = "zod", // oops, typo in 1st param name!
quux = "baz",
});
This is even more of an issue because it can only be caught at runtime.
A potential solution is this:
public class MyControllerMethodRouteParameters
{
string bar { get; set; }
string quux { get; set; }
}
public MyController : Controller
{
[Route("Foo", "{" + nameof(MyControllerMethodRouteParameters.bar) + "}/{" + nameof(MyControllerMethodRouteParameters.quux ) + "}")]
public IActionResult MyControllerMethod(MyModel model) { }
}
public class RouteBuilder
{
private string GetUrl(string routeName, object routeValues) { /* as before */ }
public string GetUrl(MyControllerMethodRouteParameters params)
{
return GetUrl(GetRouteNameFor(params.GetType(), params));
}
}
But it has a large drawback in terms of developer effort: when adding a new controller method, you also have to remember to add a route parameters class, a GetUrl overload for it, and a routename => route parameters type mapping. Easy to forget to do, and it also feels like unnecessary repetition since all of the necessary parameters and their types are already defined in the RouteAttribute.
So my idea was to generate the needed code via a T4 template, by reflecting over the assembly, grabbing all RouteAttributes and pulling the route name and template out of them, then parsing the template for the property names of the route parameters class. It's this last hurdle that I've fallen at, because while I know I can probably write a regex(es) to match and extract the route params from the template, I would prefer to use existing functionality to do this.
Problem is, I can't find anything that seems like it'll do this for me. The closest appears to be the internal class System.Web.Mvc.Routing.InlineRouteTemplateParser but my experiments with it were not particularly fruitful. Is there anything I can or should be using to achieve this, or should I just give in to the dark regex god?
We are using .NET Core to build a Web API. We need to support "GetBy" functionality, e.g. GetByName, GetByType, etc. but the issue we are running into is how to depict this through routes in a Restful way as well as the method overloading not properly working with how we think the routes should be. We are using MongoDB so our IDs are strings.
I'm assuming our routes should be something like this:
/api/templates?id=1
/api/templates?name=ScienceProject
/api/templates?type=Project
and the issue is that all our methods in our controller have a single string parameter and isn't properly mapped. Should the routes me different or is there a way to properly map these routes to the proper method?
If the parameters are mutually exclusive, i.e. you only search by name or type but not by name and type, then you can have the parameter be a part of the path instead of the query-params.
Example
[Route("templates")]
public class TemplatesController : Controller
{
[HttpGet("byname/{name}")]
public IActionResult GetByName(string name)
{
return Ok("ByName");
}
[HttpGet("bytype/{type}")]
public IActionResult GetByType(string type)
{
return Ok("ByType");
}
}
This example would lead to routes like:
/api/templates/byname/ScienceProject
/api/templates/bytype/Project
If there parameters are not mutually eclusive then you should do it like suggested in the answer by Fabian H.
You can make a TemplatesController with a single get method, that can take all the arguments.
[Route("api/templates")]
public class TemplatesController : Controller
{
[HttpGet]
public IActionResult Get(int? id = null, string name = null, string type = null)
{
// now handle you db stuff, you can check if your id, name, type is null and handle the query accordingly
return Ok(queryResult);
}
}
How to have a Route which points to two different controller end points which accepts different arguments in WEB Api 2
I have two different end points declared in controller and as for the REST perspective I have to use the alpha/{aplhaid}/beta format for both the end points ,
[Authorize]
[HttpPost]
[Route("alpha/{aplhaid}/beta")]
public async Task<HttpResponseMessage> CreateAlpha(Beta beta, string projectId, [FromHeader] RevisionHeaderModel revision)
[Authorize]
[HttpPost]
[Route("alpha/{aplhaid}/beta")]
public async Task<HttpResponseMessage> CreateAlpha(List<Beta> betas, string projectId, [FromHeader] RevisionHeaderModel revision)
Is it possible to use the same router with different parameters which points to 2 different end points in Web API 2?
If you really need to have the same route and the same ActionName, you could do it with an IHttpActionSelector.
public class CustomActionSelector : ApiControllerActionSelector, IHttpActionSelector
{
public new HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
{
var context = HttpContext.Current;
// Read the content. Probably a better way of doing it?
var stream = new StreamReader(context.Request.InputStream);
var input = stream.ReadToEnd();
var array = new JavaScriptSerializer().Deserialize<List<string>>(input);
if (array != null)
{
// It's an array
//TODO: Choose action.
}
else
{
// It's not an array
//TODO: Choose action.
}
// Default.
var action = base.SelectAction(controllerContext);
return action;
}
public override ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor)
{
var lookup = base.GetActionMapping(controllerDescriptor);
return lookup;
}
}
In your WebApiConfig:
config.Services.Replace(
typeof(IHttpActionSelector),
new CustomActionSelector());
Example for your an Controller:
public class FooController: ApiController
{
[HttpPost]
public string Post(string id)
{
return "String";
}
[HttpPost]
public string Post(List<string> id)
{
return "some list";
}
}
The solution has some big downsides, if you ask me. First of, you should look for a solution for using this CustomActionSelector only when needed. Not for all controllers as it will create an overhead for each request.
I think you should reconsider why you really need two have to identical routes. I think readability will be suffering if the same route accepts different arguments. But that's just my opinion.
I would use different routes instead.
Overload web api action method based on parameter type is not well supported.
But what about attribute based routing ?
You can find out a good example here
Route constraints let you restrict how the parameters in the route template are matched. The general syntax is "{parameter:constraint}". For example:
[Route("users/{id:int}"]
public User GetUserById(int id) { ... }
[Route("users/{name}"]
public User GetUserByName(string name) { ... }
And I think this link must be helpful
Use one route and call the other controller inside from the first controller.
I am a newbie when it comes to C#, but I need to use it for a project at work.
I am building a web page that is using jQuery to call a C# program. The C# program will connect to a SQL server, retrieve data for agencies and return it to the calling webpage as JSON.
I have all that working, I can get both a single agency and a collection of agencies and return it properly. Below is the code:
public class AgencyController : ApiController
{
// GET: api/Agency
public List<AgencyData> Get()
{
//var queryValues = Request.RequestUri.ParseQueryString();
//string filter = queryValues.Get("filter").ToString();
List<AgencyData> json;
json = SQLAllAgencyData("");
return json;
}
// GET: api/Agency/5
public List<AgencyData> Get(string id)
{
List<AgencyData> json;
json = SQLAgencyData(id);
return json;
}
What I want to do now is to be able to pass additional information to the C# program. Something like this:
www.domain.com/api/Agency?state=TX&city=Dallas
I can not figure out how to do that. All the examples I found result in build errors.
Here are a couple of links I tried:
http://forums.asp.net/t/1072321.aspx?How+to+get+parameter+in+url+by+C+for+net
Is there a way to get all the querystring name/value pairs into a collection?
You can also see the two commented out line in my code, they also don't work.
I figure that Request is never set to anything, or defined/declared, but I haven't been able to find an example of how to do that.
Suggestions?
There is no need to read the query string, the WEB API model binder will bind any query string parameters to parameters of your action method... I have never known a scenario where I needed to manually parse the query string
With Attribute Routing:
Attribute routing allows you to specifiy nullable parameters, you will need to enable attribute routing which you can find hundreds of tutorials on.
[Route("Agency/{state?}/{city?}")
public List<AgencyData> Get(string state = null, string city = null)
{
List<AgencyData> json;
json = SQLAllAgencyData("");
return json;
}
This would make the url look like this...
http://xxxxxx.com/api/Agency/Texas/Dallas
I am however almost sure your query string syntax would work too however you will need to try that.
Without Attribute Routing:
If you do not want to add attribute routing to Web API you can also add overloaded action methods to the controller..
// /api/Agency
public List<AgencyData> Get()
{
var json = SQLAllAgencyData("");
return json;
}
// /api/Agency?state=texas&city=dallas
public List<AgencyData> Get(string state, string city)
{
// Params will be equal to your values...
var json = SQLAllAgencyData("");
return json;
}
EDIT: Turns out there is no need to overload the action method... simply set the parameter defaults to null... (overload seems cleaner though)
// /Agency/
// /Agency?state=Texas&city=Dallas
public List<AgencyData> Get(string state = null, string city = null)
{
// Check for null.. etc.
}
Edit: To make this work I have used the default routing config...
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
if you want state and city as parameter of method than just add that to parameter of your method and parameters name should match with query string parameter names
Get(String state, String city)
You can directly accept the query parameters as method parameters and the query string values can be used in your method.
public List<AgencyData> Get(String state, String city)
{
//var queryValues = Request.RequestUri.ParseQueryString();
//string filter = queryValues.Get("filter").ToString();
List<AgencyData> json;
json = SQLAllAgencyData("");
return json;
}
How do I generate a URL pointing to a controller action from a helper method outside of the controller?
You could use the following if you have access to the HttpContext:
var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
You can use LinkGenerator . It's new feature in Microsoft.AspNetCore.Routing namespace and has been added in Aug 2020 .
At first you have to inject that in your class :
public class Sampleervice
{
private readonly LinkGenerator _linkGenerator;
public Sampleervice (LinkGenerator linkGenerator)
{
_linkGenerator = linkGenerator;
}
public string GenerateLink()
{
return _linkGenerator.GetPathByAction("Privacy", "Home");
}
}
For more information check this
Using L01NL's answer, it might be important to note that Action method will also get current parameter if one is provided. E.g:
editing project with id = 100
Url is http://hostname/Project/Edit/100
urlHelper.Action("Edit", "Project")
returns http://hostname/Project/Edit/100
while urlHelper.Action("Edit", "Project", new { id = (int?) null });
returns http://hostname/Project/Edit
Since you probably want to use the method in a View, you should use the Url property of the view. It is of type UrlHelper, which allows you to do
<%: Url.Action("TheAction", "TheController") %>
If you want to avoid that kind of string references in your views, you could write extension methods on UrlHelper that creates it for you:
public static class UrlHelperExtensions
{
public static string UrlToTheControllerAction(this UrlHelper helper)
{
return helper.Action("TheAction", "TheController");
}
}
which would be used like so:
<%: Url.UrlToTheControllerTheAction() %>
Pass UrlHelper to your helper function and then you could do the following:
public SomeReturnType MyHelper(UrlHelper url, // your other parameters)
{
// Your other code
var myUrl = url.Action("action", "controller");
// code that consumes your url
}