Can´t read odata in mvc controller - odata

I have the following url:
http://localhost:64863/api/Entity/getStatus?%24skip=0&%24top=25&%24inlinecount=allpages&_=1473445898026
My question is how can I read skip and top in controller. This is my controller signature:
[HttpGet("getStatus")]
public JsonResult GetStatus(
string filter,
int skip,
int top)
{

The following query string
%24skip=0&%24top=25
will be available in Request.QueryString with the following keys: $skip and $top. You won't be able to change your controller parameter names to $skip and $top since you'll get an error in Visual Studio and won't be able to compile, so you can remove the skip and top parameter and get the %24skip and %24top values from Request.QueryString in your controller
[HttpGet("getStatus")]
public JsonResult GetStatus(
string filter)
{
string skip = string.Empty;
string top = string.Empty;
if (Request.QueryString["$skip"] != null)
{
skip = Request.QueryString["$skip"];
}
if (Request.QueryString["$top"] != null)
{
top = Request.QueryString["$top"];
}
// do whatever you want with skip and top variable

This is the code i added after get QueryString:
private string getParameterFromUrl(string parameter)
{
string url = Request.QueryString.Value;
Match match = Regex.Match(url, parameter + "=([^&]*)");
return match.Result("$1");
}
Where parameter is skip or top in my case

Related

How to map querystring to action method parameters in MVC?

I have a url http://localhost/Home/DomSomething?t=123&s=TX and i want to route this URL to the following action method
public class HomeController
{
public ActionResult DoSomething(int taxYear,string state)
{
// do something here
}
}
since the query string names does not match with action method's parameter name, request is not routing to the action method.
If i change the url (just for testing) to http://localhost/Home/DomSomething?taxYear=123&state=TX then its working. (But i dont have access to change the request.)
I know there is Route attribute i can apply on the action method and that can map t to taxYear and s to state.
However i am not finding the correct syntax of Route attribute for this mapping, Can someone please help?
Option 1
If Query String parameters are always t and s, then you can use Prefix. Note that it won't accept taxYear and state anymore.
http://localhost:10096/home/DoSomething?t=123&s=TX
public ActionResult DoSomething([Bind(Prefix = "t")] int taxYear,
[Bind(Prefix = "s")] string state)
{
// do something here
}
Option 2
If you want to accept both URLs, then declare all parameters, and manually check which parameter has value -
http://localhost:10096/home/DoSomething?t=123&s=TX
http://localhost:10096/home/DoSomething?taxYear=123&state=TX
public ActionResult DoSomething(
int? t = null, int? taxYear = null, string s = "", string state = "")
{
// do something here
}
Option 3
If you don't mind using third party package, you can use ActionParameterAlias. It accepts both URLs.
http://localhost:10096/home/DoSomething?t=123&s=TX
http://localhost:10096/home/DoSomething?taxYear=123&state=TX
[ParameterAlias("taxYear", "t")]
[ParameterAlias("state", "s")]
public ActionResult DoSomething(int taxYear, string state)
{
// do something here
}

How to filter results in controller operating on getting string from view in MVC5

I have a "video" search box in view that takes string input from user and pass back to controller...
Controller then operates on the string and returns data (Videos Name) to view.
I want to include the ".contain()" function to operate on string which contains the video.
Note: Controller returns exact same result as requested Name.
Code is as follows:
public ActionResult SearchVideos(string str)
{
IQueryable<VideoDM> videodm = db.Video.Where(search => search.Title==str);
if(str != null)
{
return View(videodm);
}
else
{
string err = "No Video Found";
return View(err);
}
}
Is there a way to add contain() function after where() to tell the controller to return the result that contains the string "str"?
Add .contain() inside where clause.
IQueryable<VideoDM> videodm = db.Video.Where(search => search.Title.Contains(str));

Routing with parameter conflicts issue

MY route config :
routes.MapRoute(
"LastTwoRoute",
"thong-ke-ket-qua-xo-so-2-so-cuoi/{cityID}/{pnumbers}/{pdays}/{ponlySpecial}",
new { controller = "LastTwo", action = "Index",
cityID = "MB",
pnumbers = "",
pdays = 1000,
ponlySpecial = false
});
The controller :
[HttpGet]
public ActionResult Index(string cityID, string pnumbers, int pdays, bool ponlySpecial)
{
[HttpGet]
public ActionResult Index(string cityID, string pnumbers, int pdays, bool ponlySpecial)
{
LastTwoParameters lastTwoParameters = new LastTwoParameters();
lastTwoParameters.listCities = Common.GetDropDownCitiesList();
lastTwoParameters.Numbers = pnumbers;
lastTwoParameters.Days = pdays;
lastTwoParameters.OnlySpecial = ponlySpecial;
lastTwoParameters.listLastTwoResult = new List<getReport_LastTwo_Result>();
if (TempData["Redirection"] != null || !string.IsNullOrEmpty(pnumbers) )
{
if (!string.IsNullOrEmpty(cityID) && pdays > 0)
{
using (KQXS context = new KQXS())
{
lastTwoParameters.listLastTwoResult = context.getReport_LastTwo(cityID, pnumbers, pdays, ponlySpecial).ToList();
}
}
}
return View(lastTwoParameters);
}
[HttpPost]//Run action method on form submission
public ActionResult Index(List<Cities> c, string cityID, string numbers, int days, bool onlySpecial)
{
TempData["Redirection"] = true;
return RedirectToRoute("LastTwoRoute", new {
cityID = (string.IsNullOrEmpty(cityID) ? "MB" : cityID ),
pnumbers = (string.IsNullOrEmpty(numbers) ? string.Empty : numbers) ,
pdays = (days == 0 ? 1000 : days),
ponlySpecial = onlySpecial});
}
When I frist access the controller :
and hit the submit button without entering/modifying any parameter, there are no errors :
but if I modify the third or the fourth parameter, I will have this error :
No route in the route table matches the supplied values.
I debuged the code, and at the line RedirectToRoute in HttpPost, every parameters are about the same except the parameter that I modified. I can't think of a reason why is this error happening!
If I enter/modified the second parameter (the second text box counting from top to bottom), I have no errors either!
Any help is greatly appreciated!
P/s : If this is not clarify enough for you because of my poor English, I can provide a screen video which records how I get the error!
You have pnumbers = "" in your route but it's not marked as an optional field (and you wouldn't be able to have it as optional if it's in the middle with required fields around it).
Try defaulting it to "0" or something.
Another alternative is to move this option to the end of the required parameters and mark it as optional like:
pnumbers = UrlParameter.Optional
It's worth installing route debugger if you are having routing issues as it adds a nice interface at the bottom of the page which shows which routes will trigger and which wont. It's essential with complex routes IMO.

How to get GET parameters with ASP.NET MVC ApiController

I feel a bit absurd asking this but I can't find a way to get parameters for a get request at
/api/foo?sort=name for instance.
In the ApiController class, I gave a public string Get(). Putting Get(string sort) makes /api/foo a bad request. Request instance in the ApiController is of type System.Net.Http.HttpRequestMessage. It doesn't have a QueryString or Parameters property or anything.
The ApiController is designed to work without the HttpContext object (making it portable, and allowing it to be hosted outside of IIS).
You can still access the query string parameters, but it is done through the following property:
Request.GetQueryNameValuePairs()
Here's an example loop through all the values:
foreach (var parameter in Request.GetQueryNameValuePairs())
{
var key = parameter.Key;
var value = parameter.Value;
}
You could just use
HttpContext.Current.Request.QueryString
Here's an example that gets the querystring q from the request and uses it to query accounts:
var q = Request.GetQueryNameValuePairs().Where(nv => nv.Key =="q").Select(nv => nv.Value).FirstOrDefault();
if (q != null && q != string.Empty)
{
var result = accounts.Where(a=>a.Name.ToLower().StartsWith(q.ToLower()));
return result;
}
else
{
throw new Exception("Please specify a search query");
}
This can be called then like this:
url/api/Accounts?q=p
Get all querystring name/value pairs into a variable:
IEnumerable<KeyValuePair<string, string>> queryString = request.GetQueryNameValuePairs();
Then extract a specified querystring parameter
string value = queryString.Where(nv => nv.Key == "parameterNameGoesHere").Select(nv => nv.Value).FirstOrDefault();
You can also use the following
var value = request.GetQueryNameValuePairs().Where(m => m.Key == "paramName").SingleOrDefault().Value;
if we have a proper model for that request
for example
public class JustModel
{
public int Id {get;set;}
public int Age {gets;set;}
}
and query like this
/api/foo?id=1&Age=10
You could just use [FromUri] attribute
For example
public IHttpActionResult GetAge([FromUri] JustModel model){}
You're trying to build an OData webservice? If so, just return an IQueryable, and the Web API will do the rest.
Adding a default value does the job:
public string Get(string sort="")

Url.Action based on the current route

I'd like to generate a new URL based on the existing route, but will add a new parameter 'page'
Here are a few examples:
old: ~/localhost/something?what=2
new: ~/localhost/something?what=2&page=5
old: ~/localhost/Shoes
new: ~/localhost/Shoes/5
I can not just append &page=5 to existing url because routes may be different.
Some use the query string and some do not.
I had a similar issue, and took the approach of extending the UrlHelper. The code in the View looks like:
Page 2
The UrlHelper extension looks like:
using System.Web.Mvc;
using System.Web.Routing;
using System.Collections.Specialized;
public static class UrlHelperExtension
{
public static string AddPage(this UrlHelper helper, int page)
{
var routeValueDict = new RouteValueDictionary
{
{ "controller", helper.RequestContext.RouteData.Values["controller"] },
{ "action" , helper.RequestContext.RouteData.Values["action"]}
};
if (helper.RequestContext.RouteData.Values["id"] != null)
{
routeValueDict.Add("id", helper.RequestContext.RouteData.Values["id"]);
}
foreach (string name in helper.RequestContext.HttpContext.Request.QueryString)
{
routeValueDict.Add(name, helper.RequestContext.HttpContext.Request.QueryString[name]);
}
routeValueDict.Add("page", page);
return helper.RouteUrl(routeValueDict);
}
}
A couple of notes: I check for the ID, since I don't use it in all my routes. I add the Page route value at the end, so it is the last url parameter (otherwise you could add it in the initial constructor).
This seems like a good approach:
// Clone Current RouteData
var rdata = new RouteValueDictionary(Url.RequestContext.RouteData.Values);
// Get QueryString NameValueCollection
var qstring = Url.RequestContext.HttpContext.Request.QueryString;
// Pull in QueryString Values
foreach (var key in qstring.AllKeys) {
if (rdata.ContainsKey(key)) { continue; }
rdata[key] = qstring[key];
}
// Update RouteData
rdata["pageNo"] = "10";
// Build Url
var url = Url.RouteUrl(rdata);
and it avoids collisions such as ?controller=example&action=problem etc.
You could reconstruct a url by pulling out the parts of the existing route by way of the RouteData object. For instance, the following would render a url with the controller and action of the current route:
<%=Url.RouteUrl(new { controller = ViewContext.RouteData.Values["controller"],
action = ViewContext.RouteData.Values["action"] }) %>
To get you started, you could go with something like a custom extension method that generates the url with an additional "page" parameter. Adjust as necessary:
public static string UrlWithPage(this UrlHelper urlHelper, string name, int page)
{
string url = urlHelper.RouteUrl(
new {
controller = urlHelper.RequestContext.RouteData.Values["controller"],
action = urlHelper.RequestContext.RouteData.Values["action"],
id = urlHelper.RequestContext.RouteData.Values["id"],
page = page
}
);
return "" + name + "";
}
This will construct a properly formatted link based on the routing configuration, whether page is real segment in the url or just appended as a querystring.

Resources