Rewriting dynamic URL ASP.net - asp.net

I know how to rewrite url into web.conf but the problem is that I have to know from the id given in the url wich name to put into the rewrited url for example
foo/5 should be foo/bar because in the database the id 5 have the name "bar"
i also have the class method that tell me which name is assignd the witch id
So, I want to call the class from web.config to take the exact name for the corresponding id and then rewrite the URL
I saw the possibility of using custom configuration class but do not know how to use it.
Could you please tell me how or give me one other suggestion?

The general concept is that I take an incoming url (request) and map that to a specific page. Like /blog/my-awesome-post will be rewritten to Blog.aspx?id=5.
public class UrlRewriteModule : IHttpModule
{
public void Dispose()
{
// perform cleanup here if needed.
}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest); // attach event handler for BeginRequest event.
}
void context_BeginRequest(object sender, EventArgs e)
{
// get the current context.
HttpContext context = ((HttpApplication)sender).Context;
// the requested url
string requestedUrl = context.Request.Path; // e.g. /blog/my-awesome-post
// if you want to check for addtional parameters from querystring.
NameValueCollection queryString = context.Request.QueryString;
// perform db calls, lookups etc to determine how to rewrite the requested url.
// find out what page to map the url to.
// lets say that you have a page called Blog, and 'my-awesome-post' is the title of blog post with id 5.
string rewriteUrl = "Blog.aspx?id=5";
// rewrite to the path you like.
context.RewritePath(rewriteUrl);
}
}
You would need to add the module to the modulelist in web.config:
IIS pre version 7.:
<system.web>
<httpModules>
<add name="UrlRewriteModule" type="Assembly.Name.UrlRewriteModule, Your.Namespace.Here" />
....
</httpModules>
.....
</system.web>
IIS 7 and newer:
<system.webServer>
<modules>
<add name="UrlRewriteModule" type="Assembly.Name.UrlRewriteModule, Your.Namespace.Here" />
....
</modules>
....
</system.webServer>

Related

Reading query-string in asp.net without specifying any page name

How to read any strings in a aspx page.
example: http://foo.com/bike stand
I want to read/get the strings in a specified aspx page.
expected page string is bike stand
expected page is getstring.aspx
Here i like to read the string and redirect to specified page.
Note: I like to do this in just ASP.Net (Not with MVC)
You can probably solve this using a Route. I have made a simple demo, that you can try out in just a couple of minutes. In the Global.asax.cs file, add this method:
void RegisterRoutes(RouteCollection routes)
{
routes.MapPageRoute("Products",
"Products/{product}", "~/getstring.aspx",
false,
new RouteValueDictionary { { "product", "NoneSelected" } }
);
}
In the same file, in the already existing void Application_Start(object sender, EventArgs e) method, add RegisterRoutes(RouteTable.Routes);:
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
With this, you have configured a Route which will take a request like this:
http://foo.com/Products/bike%20stand
and map it to getstring.aspx. Note that I have url encoded the space in the url.
In getstring.aspx you can access the value ("bike stand") like this:
protected void Page_Load(object sender, EventArgs e)
{
string routeValue = "";
if (RouteData.Values.ContainsKey("product"))
routeValue = RouteData.Values["product"].ToString();
//routeValue now contains "bike stand"
SelectedProduct.Text = routeValue;
}
I have set up the Route in this sample on the path "Products" beneath the application folder. I don't recommend that you setup your route directly under the application folder as in the question. You can do it though if you absolutely want to:
void RegisterRoutes(RouteCollection routes)
{
routes.MapPageRoute("Products",
"{product}", "~/getstring.aspx",
false,
new RouteValueDictionary { { "product", "NoneSelected" } }
);
}
It may not the best way to fulfill your need but if you want to get the string part from URL you may use URI Segments.
HttpContext.Current.Request.Url.Segments.Select(x=>x.TrimEnd‌​('/')).Skip(2).ToArr‌​ay();
OR
new Uri("http://www.someurl.com/foo/xyz/index.htm#extra_text").Segments
Results: [ "/", "foo/", "xyz/", "index.html" ]
After reading string you can do whatever you want like redirection etc
You could use the IIS URL Rewrite Module for this. When installed you can create a rule in the Web.Config System.Webserver node that rewrites the url so the string can be processed in code behind as a QueryString.
<rewrite>
<rules>
<rule name="getString" stopProcessing="true">
<match url="^([a-z0-9- /]+)$" ignoreCase="true"/>
<action type="Rewrite" url="getstring.aspx?string={R:1}"/>
</rule>
</rules>
</rewrite>
Then you can simply get the string value with this:
string getString = Request.QueryString["string"];
But his will create a problem if there are other pages than getstring.aspx than need to be accessed since every request is now being send to getstring.aspx. Maybe it's better to use a prefix so that you can identify the request URL as being one that has a string.
http://foo.com/getstring/bike stand
<match url="^getstring/([a-z0-9- /]+)$" ignoreCase="true"/>

HttpRequest.Form collection gets cleared after Managed HttpModule

I’m suffering this issue I can’t find an explanation for.
Have a website that handles ASP and ASPX requests.
All requests run through a custom managed module, named MyModule, let’s say for “logging purposes”.
This is the WebConfig:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="MyModule" type="MySample.MyModule" preCondition="managedHandler" />
</modules>
</system.webServer>
</configuration>
So, if a form is posted to /action.asp via AJAX, an html form, or whatever, on /action.asp I can see and print the data on the Request.Form collection.
This is /action.asp
<%#LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<%
dim count
count = Request.Form.Count
Response.write("Result: " & count)
Response.End()
%>
But, if in my custom managed module I just “PEEK” at the form collection before it’s handled by the ASP page, the collection disappears, it’s no longer available to /action.asp
This is the MyModule:
namespace MySample
{
public class MyModule : IHttpModule
{
public MyModule()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += context_BeginRequest;
}
void context_BeginRequest(object sender, EventArgs e)
{
/*
* ALL REQUESTS PASS THROUGH THIS POINT BEFORE CONTINUING.
* COUNTING THE ITEMS ON THE FORM WILL CAUSE THE FORM-COLLECTION
* TO BE CLEARED WHEN IT'S HANDLED BY ASP.
*/
int count = HttpContext.Current.Request.Form.Count;
}
public void Dispose()
{
}
}
}
It’s extremely odd. If I “comment” the count line, the form collection is handled unmodified to the ASP page. I just have to peek at it to run it.
I want to find an explanation for this backed up with some documentation, not just a hunch.
I can’t set to false the runAllManagedModulesForAllRequests, this is not an option.
I debugged the request through different .NET method calls, and many things happen when you query the Form object on .NET HttpRequest object,
// Form collection
/// Gets a collection of Form variables.
public NameValueCollection Form {
get {
EnsureForm();
if (_flags[needToValidateForm]) {
_flags.Clear(needToValidateForm);
ValidateHttpValueCollection(_form, RequestValidationSource.Form);
}
return _form;
}
}
// Populates the Form property but does not hook up validation.
internal HttpValueCollection EnsureForm() {
if (_form == null) {
_form = new HttpValueCollection();
/// THE FOLLWING METHOD AS A LOT OF SUB-CALLS AS WELL
if (_wr != null)
FillInFormCollection();
_form.MakeReadOnly();
}
return _form;
}
Is what I am experiencing an expected behavior ? What’s the documentation or the reasoning to back up this behavior ?

MVC5 DisplayModes - Views get mixed up

I have a "OperaMini" displaymode, and then a _Layout.OperaMini.cshtml layout.
This works okay, until I add Output caching. I use this cache profile:
<add name="Cache1HourVaryByAll" duration="3600" enabled="true" varyByParam="*" />
If the first hit on a page is from an OperaMini user agent, then all subsequent requests (regardless of their user agent) get the OperaMini page.
I have tried suggestions listed on this workitem, FixedDisplayModes etc but I cant get it to work.
I also use HttpRuntime.Cache for some objects, could this be causing issues?
This was supposed to be fixed in MVC5? Or am I doing something wrong?
You'll have to introduce a (pseudo) Vary-By-DisplayMode mechanism:
Global.asax:
public override string GetVaryByCustomString(HttpContext context, string arg)
{
if (arg.ToLower() == "displaymode")
{
var currentDisplayMode = DisplayModeProvider.Instance.Modes.FirstOrDefault(x => x.CanHandleContext(new HttpContextWrapper(context)));
return "displayMode=" + currentDisplayMode.DisplayModeId;
}
return base.GetVaryByCustomString(context, arg);
}
Web.Config:
<add name="Cache1HourVaryByAll"
duration="3600"
enabled="true"
varyByParam="*"
varyByCustom="displaymode" />

How to use Custom SiteMapProvider in ASP NET MVC?

I am currently trying to implement a Custom SiteMap Provider. I have read several tutorials about it, and followed their lead.
I have created a subclass of XmlSiteMapProvider named MySiteMapProvider which is located in MyProject.Security.
I have added the following code to the system.web section of my Web.config:
<siteMap defaultProvider="MySiteMapProvider" enabled="true">
<providers>
<add name="MySiteMapProvider"
description="Custom SiteMap provider."
type="MyProject.Security.MySiteMapProvider "
siteMapFile="Web.sitemap"
securityTrimmingEnabled="true" />
</providers>
</siteMap>
But I am sure that my Provider is not used correctly. I couldn't even start with the implementation. To verify that I have included the following (pseudo) implementation:
public override bool IsAccessibleToUser(System.Web.HttpContext context, System.Web.SiteMapNode node)
{
Debug.Print("Hello World");
throw new Exception();
return base.IsAccessibleToUser(context, node);
}
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection attributes)
{
Debug.Print("Hello World");
throw new Exception();
base.Initialize(name, attributes);
}
public override SiteMapNode BuildSiteMap()
{
Debug.Print("Hello World");
throw new Exception();
return base.BuildSiteMap();
}
But I can use the site and navigate as much as I want to, no Exception comes up and the Debug console shows no Hello World at all.
Did I forget something important?
Instead of implementing my own Provider, I went along with the MvcSiteMapProvider.
The customization of the behaviour that I needed to implement was realized in one day with dynamic sitemaps and a custom SiteMapNodeVisibilityProvider.
I also considered implementing the whole SiteMapProvider, maybe on SQL basis, and I am glad that I did not have to do it.
Try calling System.Web.SiteMap.RootNode from code.

Page Render Time in ASP.MVC in trace

I want to check render time of each page in asp.net mvc application.
i am using asp.net tracing. i have override the OnActionExecuting and OnActionExecuted methods on the BaseController class.
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
string controler = filterContext.RouteData.Values["controller"].ToString();
string action = filterContext.RouteData.Values["action"].ToString();
StartTime =System.DateTime.Now;
System.Diagnostics.Trace.Write(string.Format("Start '{0}/{1}' on: {2}", controler, action, System.DateTime.Now.UtilToISOFormat()));
}
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
string controler = filterContext.RouteData.Values["controller"].ToString();
string action = filterContext.RouteData.Values["action"].ToString();
var totalTime = System.DateTime.Now - this.StartTime;
System.Diagnostics.Trace.Write(totalTime.ToString());
System.Diagnostics.Trace.Write(string.Format("End '{0}/{1}' on: {2}", controler, action, System.DateTime.Now.UtilToISOFormat()));
}
in OnActionExecuted method i get total time. how can i show this time in my http://localhost:51335/Trace.axd report?
Even i had set Trace="true" in <%# Page %> on every page also.
Classic ASP.NET uses the following within your aspx code behind: Page.Trace.Write(totalTime.ToString());
In MVC you generally use System.Diagnostics.Trace.Write(... as you have done, so this code is correct.
Try this in your web.config. It routes System.Diagnostics.Trace to ASP.NET tracing:
<system.diagnostics>
<trace>
<listeners>
<add name="WebPageTraceListener"
type="System.Web.WebPageTraceListener, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
</listeners>
</trace>
</system.diagnostics>
Another thing that you could try is using the Controller.HttpContext.Trace instead. I am unable to test that right now as I am writing this from my phone, so please let me know whether that works.
This page shows you more info on how to make all System.Diagnostics.Trace messages appear un your Trace.axd - http://msdn.microsoft.com/en-us/library/b0ectfxd%28v=VS.85%29.aspx

Resources