I would like to "intercept"/alter the OData query that's generated when using OData with the Web API.. but I'm not entirely sure of how to "extract" the generated query.. I assume that the OData filter,expands and more some how gets generated to some sort of expression tree or some sort of query.. and if that's the case, then that's the type of query I would like to be able to alter before its sent to the database as an SQL-command.
I have searched the net for some way of extracting the generated expression tree.. but hasn't be able to find sufficient information, so I was sort of hoping that someone here has some more insight of how the whole OData-"framework" works..
Any ideas of where to start?
You can alter Odata url before it is executed. Inherit from EnableQueryAttribute class and change url. Following is a real case to change guid string format to hexadecimal string format before it's sent to oracle.
public class EnableQueryForGuid : EnableQueryAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var url = actionContext.Request.RequestUri.OriginalString;
var newUrl = ModifyUrl(url);
actionContext.Request.RequestUri = new Uri(newUrl);
base.OnActionExecuting(actionContext);
}
private string ModifyUrl(string url)
{
Regex regex = new Regex(#"%27([A-Za-z0-9]{32})%27");
var res = regex.Matches(url);
if (res.Count > 0)
{
var guidPart = res[0].Value.Remove(0, 3);
guidPart = guidPart.Remove(guidPart.Length - 3, 3);
var guidValue = new Guid(BitConverter.ToString((new Guid(guidPart)).ToByteArray()).Replace("-", ""));
url = url.Replace(res[0].Value, guidValue.ToString());
}
return url;
}
}
then use this new attribute on your controller method:
[HttpGet]
[EnableQueryForGuid]
[ODataRoute("GetSomething")]
public IHttpActionResult GetSomething()
{
....
}
original query:
OData/GetSomething?&$filter=MyGuid%20eq%20%272C3C7BC0EC7FA248B0DEE3DAA371EE73%27
altered query:
OData/GetSomething?&$filter=MyGuid%20eq%20e5794d6a-5db1-475a-8c49-0f91a8f53c8a
Related
I want to generate an url which uses regular expression like (currentUrlRegex:
currentUrlRegex = #"https://www.website.com/[a-z]{2})-[a-z]{2})/file/(.*)";
and will be redirected to:
toUrlRegex = #"https://www.website.com/$1-$2/file/system/$3";
If someone access like: https://www.website.com/en-en/file/123.png then redirects to https://www.website.com/en-en/file/system/123.png
I want to match current url from request (in ASP.NET MVC) with currentUrlRegex. If match then redirect to an url matched in toUrlRegex with transformation.
I have those regex urls in a file which is managed from CMS (can be added, deleted, renamed, etc)
I created an HTTP module:
public void Init(HttpApplication context)
{
_context = context;
context.PostResolveRequestCache += ContextOnPostResolveRequestCache;
}
private void ContextOnPostResolveRequestCache(object sender, EventArgs eventArgs)
{
string currentUrl = _context.Request.Url.GetLeftPart(UriPartial.Path).TrimEnd('/');
// read all kind of regex urls from a file into a list of RedirectModel
string redirectUrl = string.Empty;
foreach (RedirectModel redirectModel in list) {
try {
string url = new Uri(redirectModel.FromUrl).GetLeftPart(UriPartial.Path).TrimEnd('/');
if (url.Equals(currentUrl, StringComparison.InvariantCultureIgnoreCase)) {
redirectUrl = redirectModel.ToUrl;
break;
}
} catch {
// use regex here when Uri is invalid (contains *,),(, etc)
}
}
if (!string.IsNullOrWhiteSpace(redirectUrl)) {
_context.Response.RedirectPermanent(redirectUrl);
}
}
and RedirectModel has two simple properties of string type: FromUrl and ToUrl.
Can you help me how to achieve regex side ? For simple url I managed
Use Regex.Replace and the strings mostly as you provided them, just with corrected parenthesis in the search pattern.
var input = #"https://www.website.com/en-en/file/123.png";
var output = Regex.Replace(
input,
#"https://www.website.com/([a-z]{2})-([a-z]{2})/file/(.*)",
#"https://www.website.com/$1-$2/file/system/$3");
The URL conversion may look something like this
var input = #"https://www.website.com/en-en/file/123.png";
Regex rgx = new Regex(#"https://www.website.com/([a-z]{2})-([a-z]{2})\/file\/(.*)");
MatchCollection m = rgx.Matches(input);
if (m.Count > 0 && m.Count == 1)
{
var matchGroup = m[0].Groups;
var redirecturl = string.Format("https://www.website.com/{0}-{1}/file/system/{2}", matchGroup[1].Value, matchGroup[2].Value, matchGroup[3].Value);
}
I have a security application called Siteminder. It creates unique URLS for every authentication. HTTPS://SITE/idp/**RANDOMURLSTRING**/resumeSAML20/idp/startSSO.ping
How can i capture the Unique URL and have the test continue to login.
A webtest assumes the next URL in the process. It does not support[Or I don't know how] a unique redirect to a random URL. Does anyone know of a way to handle this case?
EDIT:
My Solution -- Replace the SessionID with {{SessionID}} in all the URLS and use this extraction rule
public class ExtractSiteMinderCustomUrl : ExtractionRule
{
public string SiteMinderSessionID { get; private set; }
// The Extract method. The parameter e contains the web performance test context.
//---------------------------------------------------------------------
public override void Extract(object sender, ExtractionEventArgs e)
{
//look for anchor tags with URLS
Regex regex = new Regex("<a\\s+(?:[^>]*?\\s+)?href=\"([^\"]+\\?[^\"]+)\"");
MatchCollection match = regex.Matches(e.Response.BodyString);
if (match.Count > 0)
{
foreach (Match ItemMatch in match)
{
if (ItemMatch.ToString().Contains("/idp/"))
{
//start and ends string from the sitemindersession is in the link on the page
e.WebTest.Context.Add(this.ContextParameterName, GetStringBetween(ItemMatch.ToString(), "/idp/", "/resume"));
e.Success = true;
return;
}
}
e.Success = false;
e.Message = String.Format(CultureInfo.CurrentCulture, "Not Found in Link : /idp/");
}
else
{
e.Success = false;
e.Message = String.Format(CultureInfo.CurrentCulture, "No href tags found");
}
}
public static string GetStringBetween(string token, string first, string second)
{
if (!token.Contains(first)) return "";
var afterFirst = token.Split(new[] { first }, StringSplitOptions.None)[1];
if (!afterFirst.Contains(second)) return "";
var result = afterFirst.Split(new[] { second }, StringSplitOptions.None)[0];
return result;
}
}
The simple answer is to have use extraction rule that gets the **RANDOMURLSTRING** then change the URLs in the requests to be, for example, HTTPS://SITE/idp/{{TheRandomString}}/resumeSAML20/idp/startSSO.ping where TheRandomString is the context parameter that holds the extracted value. Note the doubled curly braces ({{ and }}) around the context parameter.
Suppose a value returned by the first redirection needs to be captured but a normal web test would redirect again and so the response is not seen by the extraction rules. In this case need to handle the redirect explicitly. Set the Follow redirects property of the initial request to false then add extraction rule(s) to gather the wanted values. Add a new request after the initial request and use the extracted values in it as necessary. It is possible to extract the entire redirected url and set the Url field to the extracted value.
I am trying to learn and build an web application using asp.net MVC 5, WEB API 2 and AngularJS. I have already built up a good working application with custom CRUD operations. Now I want complete control on the web api controller, so that I can return data as per my requirement. For example I want to get the returned data from the following code -
string today = DateTime.Now.ToString("dd/MM/yyyy");
var appointment1 = from prescription in db.Prescriptions
where prescription.appointment == "15/01/2015"
from consultation in prescription.Consultations
select new
{
ID = prescription.id,
Name = prescription.patient_name,
Contact = prescription.patient_contact,
Task = prescription.next_task
};
var appointment2 = from consultation in db.Consultations
where consultation.next_date == "15/01/2015"
select new
{
ID = consultation.Prescription.id,
Name = consultation.Prescription.patient_name,
Contact = consultation.Prescription.patient_contact,
Task = consultation.next_task
};
var finalAppointments = appointment1.Concat(appointment2);
return finalAppointments;
I have three questions:
1) Is there any way to retrieve the returned data other than creating custom methods in my web api controller?
2) Can I just use the default method by modifying it a bit? if so then how?
3) If I SHOULD use a custom method what would be the method structure with returned data type?
Its very simple.
Note: I don't understand your first question properly. for 2que and 3que....
Lets say I'm using Get Method in Web api 2, MVC5 (I hope your are clear with HTTP methods in web api)
Which collects required data (to be returned back to angularjs).....
Now it depends upon your requirement that how many objects you want to send back to client side.
IHttpActionResult would be your return type in all HTTP methods as IHttpActionResult sends Status code via Web api....
eg;
Lets say I have PrescriptionsController.cs. So in it.
[HttpGet]
public IHttpActionResult Get()
{
var appointment1 = from prescription in db.Prescriptions
where prescription.appointment == "15/01/2015"
from consultation in prescription.Consultations
select new
{
ID = prescription.id,
Name = prescription.patient_name,
Contact = prescription.patient_contact,
Task = prescription.next_task
};
var appointment2 = from consultation in db.Consultations
where consultation.next_date == "15/01/2015"
select new
{
ID = consultation.Prescription.id,
Name = consultation.Prescription.patient_name,
Contact = consultation.Prescription.patient_contact,
Task = consultation.next_task
};
var finalAppointments = appointment1.Concat(appointment2);
// return finalAppointments; //rather I'd use below line...
return Ok(finalAppointments); // here your are concatenating two objects and want to send single object only.
}
Lets say I want to send two objects separately...
then use following way,
[HttpGet]
//public IHttpActionResult Get()
public dynamic Get()
{
var appointment1 = from prescription in db.Prescriptions
where prescription.appointment == "15/01/2015"
from consultation in prescription.Consultations
select new
{
ID = prescription.id,
Name = prescription.patient_name,
Contact = prescription.patient_contact,
Task = prescription.next_task
};
var appointment2 = from consultation in db.Consultations
where consultation.next_date == "15/01/2015"
select new
{
ID = consultation.Prescription.id,
Name = consultation.Prescription.patient_name,
Contact = consultation.Prescription.patient_contact,
Task = consultation.next_task
};
//var finalAppointments = appointment1.Concat(appointment2);
// return finalAppointments; //rather I'd use below line...
// return Ok(finalAppointments); // here your are concatenating two objects.
return new {appointment1 ,appointment2 }; // you can send multiple objects...
}
Any query feel free to ask.
I have some code that is almost working to convert an actionresult to a string.
After I execute the method EditableItem, it outputs the html stream response to a stringwriter, and then I get the html and modify it, and then I have the html in a string (with escape charachters).
My problem is that at the end of the code, I cant return a content result. I assume this is because I'm messing with the ControllerContext. I'm entirely sure if this is the problem, but this code returns a blank html page for me. But the end, the readonlyHtmlString string is full of great html code. And rendering a regular ContentResult doesn't work either. How can I remedy this?
Thanks
public ActionResult Readonly(long Id = 0, long id2 = 0)
{
var localWriter = new StringWriter();
var response = ControllerContext.RequestContext.HttpContext.Response;
response.Output = localWriter;
this.EditableItem( Id, id2 ).ExecuteResult(ControllerContext);
localWriter.Flush();
var htmlStringWithEscapes = localWriter.ToString();
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(htmlStringWithEscapes);
foreach (HtmlNode inputNode in htmlDoc.DocumentNode.SelectNodes("//input"))
{
//var disabledNode = inputNode.Clone();
inputNode.Attributes.Add("disabled", "disabled");
//inputNode.ParentNode.ReplaceChild(inputNode, disabledNode);
}
var readonlyHtmlString = htmlDoc.DocumentNode.OuterHtml;
//should return a readonly view at this point!!
//return Content(readonlyHtmlString, "text");
//this code doesn't work anymore either
return Content(String.Format("This is the Material Item Controller > Readonly and Id is {0} and id2 is {1}",Id, id2),"text");
}
I'm not sure why it wasn't working, so I scrapped the code in favor of the methods used here...
Render an MVC3 action to a string from a WCF REST service method
I want to fetch books using Amazon Product Advertising API with asp.net and C#. All the guides and codes are so confusing as to they don't give you a single method to search the books.
Is there any single stub that can be used to call the service and fetch the books based on the ISBN.
thanks
There's a good sample solution you can download.
http://aws.amazon.com/code/2480?_encoding=UTF8&queryArg=searchQuery&x=0&fromSearch=1&y=0&searchPath=code&searchQuery=Advertising
They give you a class called SignedRequestHelper, then you make a call like this:
public static void Main()
{
SignedRequestHelper helper = new SignedRequestHelper(MY_AWS_ACCESS_KEY_ID, MY_AWS_SECRET_KEY, DESTINATION);
/*
* The helper supports two forms of requests - dictionary form and query string form.
*/
String requestUrl;
String title;
/*
* Here is an ItemLookup example where the request is stored as a dictionary.
*/
IDictionary<string, string> r1 = new Dictionary<string, String>();
r1["Service"] = "AWSECommerceService";
r1["Version"] = "2009-03-31";
r1["Operation"] = "ItemLookup";
r1["ItemId"] = ITEM_ID;
r1["ResponseGroup"] = "Small";
/* Random params for testing */
r1["AnUrl"] = "http://www.amazon.com/books";
r1["AnEmailAddress"] = "foobar#nowhere.com";
r1["AUnicodeString"] = "αβγδεٵٶٷٸٹٺチャーハン叉焼";
r1["Latin1Chars"] = "ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJij";
requestUrl = helper.Sign(r1);
title = FetchTitle(requestUrl);
System.Console.WriteLine("Method 1: ItemLookup Dictionary form.");
System.Console.WriteLine("Title is \"" + title + "\"");
System.Console.WriteLine();
}
You need to use the ItemLookup (like the example) but set the IdType to ISBN. Then set the ItemId to the actual ISBN. Here are the details on ItemLookup:
docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?ItemLookup.html
I get this when I use that sample. looks like there has been a change in the API recently.
System.InvalidOperationException: There is an error in the XML document. ---> Sy
stem.InvalidOperationException: <ItemLookupResponse xmlns='http://webservices.am
azon.com/AWSECommerceService/2011-08-01'> was not expected.
To fetch books install this library (Install-Package Nager.AmazonProductAdvertising)
https://www.nuget.org/packages/Nager.AmazonProductAdvertising/
Example:
var authentication = new AmazonAuthentication("accesskey", "secretkey");
var client = new AmazonProductAdvertisingClient(authentication, AmazonEndpoint.UK);
var result = await client.GetItemsAsync("978-0261102385");