.net 4.0 Routing with QueryStrings - c#

I realize there are a ton of articles and resources out there on this subject, but all seem to only show how to move a querystring like category=shoes around the url to a differently place, like this products/{category}
Well i have the following querystring: profile.aspx?q=98c2b15f-90c3-4a7f-a33f-0e34b106877e
I was trying to implement a RoutHandler to query the DB to find the users name and create a url like mydomain.com/usersname
This is what i tried (everything is hard coded right now till i get it working):
void Application_Start(object sender, EventArgs e)
{
RegisterRoute(System.Web.Routing.RouteTable.Routes);
}
void RegisterRoute(System.Web.Routing.RouteCollection routes)
{
routes.Add("Profiles", new System.Web.Routing.Route("profile/{profile}", new RouteHandler()));
}
And this is the handler class:
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
string username = requestContext.RouteData.Values["profile"] as string;
HttpContext.Current.Items["q"] = "98c2b15f-90c3-4a7f-a33f-0e34b106877e";
return BuildManager.CreateInstanceFromVirtualPath("~/pub/profile.aspx", typeof(Page)) as Page;
}
Profile.aspx actually looks for the "q" querystring. And with the above setup, it does not find it.
What am i doing wrong? How do i route or rewrite the url so that it is pretty + keep it so the page can find the querystrings it needs?
Any help would be great. Thanks in advance.

First thing - If you are using .net framework 4 you dont need to create any handler, you can directly use MapPageRoute method to a route.
Answer to your question-
use can use foreach loop like below in handler rather than looking for "profile" specifically.
foreach (var urlParm in requestContext.RouteData.Values)
requestContext.HttpContext.Items[urlParm.Key] = urlParm.Value;
return BuildManager.CreateInstanceFromVirtualPath(VirtualPath, typeof(Page)) as IHttpHandler
and in your routed page you should check for
string userName = this.Context.Items["profile"].ToString(); // "userName" and is set as route parameters in Global.asax
You set VirtualPath in RouteHandler constructor
RouteHandler(string virPath)
{
this.VirtualPath = virPath;
}
see these links for more information-
http://www.codeproject.com/Articles/77199/URL-Routing-with-ASP-NET-4-0
http://msdn.microsoft.com/en-us/library/ie/cc668201.aspx

Related

CefSharp Search Engine Implamentation

I am working on a cefsharp based browser and i am trying to implement a search engine into the browser, but the code I have tried docent work, it doesn't really have any errors but when i star the project and type something i the text field nothing happens and it dosent load the search engine i entered into the code, the only time the textbox loads anything is when a url is typed.
This is the code used in the browser that docent work
private void LoadUrl(string url)
{
if (Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute))
{
WebUI.Load(url);
}
else
{
var searchUrl = "https://www.google.com/search?q=" + WebUtility.HtmlEncode(url);
WebUI.Load(searchUrl);
}
}
i have also tried
void LoadURl(String url)
{
if (url.StartsWith("http"))
{
WebUI.Load(url);
}
else
{
WebUI.Load(url);
}
}
i was also suggested to try
private void LoadUrl(string url)
{
if (Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute))
{
WebUI.LoadUrl(url);
}
else
{
var searchUrl = "https://www.google.com/search?q=" + Uri.EscapeDataString(url);
WebUI.LoadUrl(searchUrl);
}
}
We have here really few Information on how your code works. But what I notice is that you use WebUtility.HtmlEncode for the search query. WebUtility has also a WebUtility.UrlEncode Method, that how I understand your question makes more sense it the context. This is the documentation for the method: https://learn.microsoft.com/de-de/dotnet/api/system.net.webutility.urlencode
The Url you are generating is invalid. You need to use Uri.EscapeDataString to convert the url param into a string that can be appended to a url.
// For this example we check if a well formed absolute Uri was provided
// and load that Url, all others will be loaded using the search engine
// e.g. https://github.com will load directly, attempting to load
// github.com will load the search engine with github.com as the query.
//
if (Uri.IsWellFormedUriString(url, UriKind.Absolute))
{
chromiumWebBrowser.LoadUrl(url);
}
else
{
var searchUrl = "https://www.google.com/search?q=" + Uri.EscapeDataString(url);
chromiumWebBrowser.LoadUrl(searchUrl);
}
nothing happens and it dosent load the search engine
You need to subscribe to the LoadError event to get actual error messages. It's up to you to display errors to the user. The following is a basic example:
chromiumWebBrowser.LoadError += OnChromiumWebBrowserLoadError;
private void OnChromiumWebBrowserLoadError(object sender, LoadErrorEventArgs e)
{
//Actions that trigger a download will raise an aborted error.
//Aborted is generally safe to ignore
if (e.ErrorCode == CefErrorCode.Aborted)
{
return;
}
var errorHtml = string.Format("<html><body><h2>Failed to load URL {0} with error {1} ({2}).</h2></body></html>",
e.FailedUrl, e.ErrorText, e.ErrorCode);
_ = e.Browser.SetMainFrameDocumentContentAsync(errorHtml);
}
For testing purposes you can also copy and paste the searchUrl string you've generated and try loading it in Chrome to see what happens, you should also get an error.

how to get dynamic value using string instead of key?

I have a Web API controller looking similar to this:
public void Post([FromBody]dynamic postData)
{
foreach (var row in postData)
{
var email = row.email.Value; // ok
var eventType = row.event.Value; // cannot use because "event" is reserved by .NET, C# or whatever
}
}
I'm getting a JSON from external system which contains this "event" property (outside of my control), that I'm unable to retrieve. I've tried dozens of workaround, but none of them seemed to work in this scenario. Hopefully there is some easy way of retrieving it.
The best bet I had was using reflection like:
row.GetType().GetProperty("event").GetValue(row, null);
But didn't work as I had expected. Is there something else I can try?
Solution is to use "#" like:
row.#event.Value

Caching ASP.NET Web API with CacheCow

I am trying to implement caching using CacheCow. I have two problems:
In some cases I need to invalidate manually the cache of some resources.
For example, I have a resource that it is called purchase, and other that is called pointMovements. They are not totally connected, but doing a post in purchase, implies some changes in pointMovement. Cachecow is not detecting these changes because I am not calling the API of pointmovements. So when I call the endpoint of pointmovements, the values are cached and I cannot get the new values.
To solve this, I need to invalidate that manually, how is that possible?
There are some controllers that I don't want to cache. I am trying to use attributes for doing that but it is not working. I am following this article but the attributes are ignored.
How can I specify which controllers to cache?
I came across the same set of problems and found a solution for problem 2 (disable caching regardless of the default settings).
// This forces the server to not provide any caching by refreshing its cache table immediately (0 sec)
[HttpCacheRefreshPolicy(0)]
// This forces the client (browser) to not cache any data returned from the server (even if ETag is present) by setting the time-out to 0 and no-cache to true.
[HttpCacheControlPolicy(true, 0, true)]
public void MyController : ApiControler {... }
The attributes must be applied together for this to work. You can also control the caching at the action level by providing the same rules to each action.
I've still to figure out the solution for problem 1. but watch this space for updates.
Update
I have found a solution to problem 1.
Register the CachingHandler with your IoC container (in my case it's IUnityContainer)
Inject the ICachingHandler into your Web API controller.
To invalidate the resource, use ICachingHandler.InvalidateResource(HttpRequestMessage)
Please see a code example below. The solution has been tested.
public class Bootstrapper
{
//...
// Create a new caching handler and register it with the container.
public void RegisterCache(HttpConfiguration config, IUnityContainer container)
{
var cachingHandler = new CachingHandler(config);
// ...
container.RegisterInstance<ICachingHandler>(cachingHandler);
}
}
public class ResourceContoller : ApiController
{
private ICachingHandler _cachingHandler;
public ResourceContoller(ICachingHandler cachingHandler)
{
_cachingHandler = cachingHandler;
}
[HttpPost]
public void DeleteResource(int resourceId)
{
// Do the delete
// ...
// Now invalidate the related resource cache entry
// Construct a http request message to the related resource
// HINT: The "DefaultApi" may not be your api route name, so change this to match your route.
// GOTCHA: The route matching mechanism is case sensitive, so be aware!
var relatedResource = new HttpRequestMessage(HttpMethod.Get, Url.Link("DefaultApi", new {controller = "linkedresource", action = "getlinkedresource", id: resourceId}));
// Invalidate the resource with the caching handler.
_cachingHandler.InvalidateResource(relatedResource);
}
}
Sorry for the late response.
As #Tri Q said, the way to do this is to use attributes which I have explained in this blog:
http://byterot.blogspot.co.uk/2013/03/rest-asp-net-wep-api-0.4-new-features-breaking-change-cachecow-server.html
I solved your #1 question using below code. Here I extend the IRoutePatternProvider interface. Remember, what you return in GetRoutePattern should match what you return in GetLinkedRoutePatterns. Only then the adding and removing will work. Try it out.
Inside Application_Start
CachingHandler cacheHandler = new CachingHandler(GlobalConfiguration.Configuration);
cacheHandler.RoutePatternProvider = new CacheRoutePatternProvider();
GlobalConfiguration.Configuration.MessageHandlers.Add(cacheHandler);
Custom Class
public class CacheRoutePatternProvider : IRoutePatternProvider
{
public string GetRoutePattern(HttpRequestMessage request)
{
string path = request.RequestUri.AbsolutePath;
if (!path.EndsWith("/"))
path += "/";
return path;
}
public IEnumerable<string> GetLinkedRoutePatterns(HttpRequestMessage request)
{
string path = request.RequestUri.AbsolutePath;
if(!path.EndsWith("/"))
path += "/";
int segmentIndex;
// return each segment of the resource heirarchy
while ((segmentIndex = path.LastIndexOf("/")) > 0)
{
path = path.Substring(0, segmentIndex);
if(path.Contains("/api/"))
yield return path + "/";
}
yield break;
}
}

Get Search Queries from UrlReferer

I'm developing a website in ASP.Net 4. One of the requirements is to log search queries that people use to find our website. So, assuming that a URL parameter named "q" is present in Referrer, I've written the following code in my MasterPage's Page_Load:
if (!CookieHelper.HasCookie("mywebsite")) CookieHelper.CreateSearchCookie();
And my CookieHelper class is like this:
public class CookieHelper
{
public static void CreateSearchCookie()
{
if (HttpContext.Current.Request.UrlReferrer != null)
{
if (HttpContext.Current.Request.UrlReferrer.Query != null)
{
string q = HttpUtility.ParseQueryString(HttpContext.Current.Request.UrlReferrer.Query).Get("q");
if (!string.IsNullOrEmpty(q))
{
HttpCookie adcookie = new HttpCookie("mywebsite");
adcookie.Value = q;
adcookie.Expires = DateTime.Now.AddYears(1);
HttpContext.Current.Response.Cookies.Add(adcookie);
}
}
}
}
public static bool HasCookie(string cookiename)
{
return (HttpContext.Current.Request.Cookies[cookiename] != null);
}
}
It seems ok at the first glance. I created a page to mimic a link from Google and worked like a charm. But it doesn't work on the host server. The reason is that when you search blah blah you see something like www.google.com/?q=blah+blah in your browser address bar. You expect clicking on your link in the results, will redirect to your site and you can grab the "q" parameter. But ,unfortunately, it is not true! Google, first redirects you to an address like:
http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CCgQFjAA&url=http%3A%2F%2Fwww.mywebsite.com%2F&ei=cks5Uof4G-aX0QXKhIGoCA&usg=AFQjCNEdmmYFpeRRRBiT_MGH5a1x9wUUlg&bvm=bv.52288139,d.d2k&cad=rja
and this will redirect to your website. As you can see the "q" parameter is empty this time! And my code gets an empty string and actually doesn't create the cookie (or whatever).
I need to know if there is a way to solve this problem and get the real "q" value. The real search term user typed to find my website. Does anybody know how to solve this?
Google stopped passing the search keyword:
http://www.searchenginepeople.com/blog/what-googles-keyword-data-grab-means-and-five-ways-around-it.html

Forms authentication + URL Rewriting gives access to secure pages

I have a problem with URL rewriting and Forms authentication in ASP.NET... Based on articles I've found on the net, I have created the following HttpModule:
public class UrlRewriter : IHttpModule
{
private UrlRewriteConfigurationSection config;
public UrlRewriter()
{
config = ConfigurationManager.GetSection("urlrewrites") as UrlRewriteConfigurationSection;
}
public void Dispose()
{
}
public void Init(HttpApplication context)
{
httpApplication.AuthorizeRequest += new EventHandler(OnAuthorizeRequest);
}
private void OnAuthorizeRequest(object sender, EventArgs e)
{
string requestedPath = HttpContext.Current.Request.Path;
foreach (UrlRewriteRule rule in config.UrlRewriteRules)
{
RegexOptions options = config.IgnoreCase ? RegexOptions.IgnoreCase : RegexOptions.None;
Regex regex = new Regex(rule.UrlPattern, options);
Match match = regex.Match(requestedPath);
if (match.Success)
{
string newPath = regex.Replace(requestedPath, rule.RewritePattern);
if (!String.IsNullOrEmpty(newPath))
{
HttpContext.Current.RewritePath(newPath);
return;
}
}
}
}
}
The problem, however, is that this somehow disables authorization! To explain assume i have the following rewrite rule:
UrlPattern: ^user/profile$
RewritePattern: protected/profile.aspx
And assume that the folder protected is setup to deny anonymous users access..
Now, when the code in the OnAuthorizeRequest runs, it correctly rewrites the path to protected/profile.aspx, however, the problem is that I am shown the page, even though I'm not logged in! If I request the page directly (http://localhost/site/protected/profile.aspx) it does not allow access to the site..
All articles I find on the net says I need to do the rewrite in AuthorizeRequest as opposed to AuthenticateRequest or BeginRequest..
Any ideas?
N.B.: I have tried moving my rewriting code to AuthenticateRequest which does seem to work, but redirection to the login page is not correct (e.g. it redirects to /login?returnUrl=protected/profile.aspx instead of login?returnUrl=user/profile)

Categories

Resources