Text URL for website in asp.net - asp.net

I am developing my blog website in asp.net.
I am saving my blog post in sql server 2005 database.
I am storing like this in my database
PostId INT IDENTITY
PostText
PostAuthor
PostedDate
IsActive
So, at the code side when user is clicking on the tag/link. It is comming like this
http://www.mysite.com/readBlog.aspx?Id=2
On the readBlog.aspx page I am reading the URL and fetching the data from the database. But this is something unprofessional. I want URL like this
Scott Gu post
How can I achieve it in simpler manner?
EDIT
It is just when I want to share the URL of my website I can do like this
http://www.mysite.com/readBlog/How-to-install-visual-studio

Take a look onto ASP.NET Routing.
Just register a route in your Global.asax:
protected void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapPageRoute("readblog",
"readblog/{id}/{title}",
"~/readBlog.aspx");
}
and then it could be accessed by using e.g.:
var path = RouteTable.Routes.GetVirtualPath(
null,
"readblog",
new RouteValueDictionary {{ "id", blogId }, { "title", URLFriendly(title) }}
).VirtualPath;
where URLFriendly produces URL-friendly version of a title (a very nice example of it could be taken from Jeff Atwood's answer). This could produce URLs like:
/readBlog/2/how-to-install-visual-studio or
/readBlog/3/something-else.

You will want to look into URL Rewriting.
Maybe take a look at a Scott Gu Post on the subject.

Related

Routing in Web forms not working

This is the code in Global.asax
void Application_Start(object sender, EventArgs e)
{
System.Web.Routing.RouteTable.Routes.MapPageRoute("Page1","{Param1}/{Param2}","~/FirstPage.aspx");
System.Web.Routing.RouteTable.Routes.MapPageRoute("Page2","Xyz/{Param3}","~/Second.aspx");
}
Now i'm trying to redirect to some page e.g. xyz/test1,xyz/test2,xyz/test3. It's always getting redirected to FirstPage, not the second page which is what is expected and i'm trying to do.
How to implement this? Any suggestions.
Please make sure below important things are met before you start creating routing,
•Define custom URL patterns that are not dependent on physical file names.
•Generate URLs based on route URL parameter values by using markup or code.
•In a routed page, retrieve values passed in URL segments by using markup or code.
Try below code to implement routing,
1. In Application_start method you can only register the routes as below,
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
Create below method after Session_End method in you global.asax file,
void RegisterRoutes(RouteCollection routes)
{
}
In the RegisterRoutes method, add the following code,
routes.MapPageRoute("SalesRoute",
"SalesReport/{locale}/{year}",
"~/sales.aspx");
This code adds a route that is named SalesRoute. You are naming this route because it has the same parameter list as the route that you will create in the following step. Assigning names to these two routes enables you to differentiate them when you generate URLs for them.
More details refer: https://msdn.microsoft.com/en-us/library/dd329551.aspx

Action filter attribute while opening image url

My requirement is like when someone opens url of any files from my asp.net mvc web site I want to track details of that user. Please note I have already added some query string, so only when opens url with that query string I want to track.
For another Action Methods I have already added query string to track via action filter. In action filter I am checking for that query string and if query string is not null and has some value then track that click.
But this logic will not work for direct URLs of files. For more details please see below example URLs.
http://wwww.example.com/Home/MyAction?trackerId=123 - TRACKING
http://wwww.example.com/Upload/Files/abc.jpg?trackerId=123 - NOT TRACKING
So any suggestions?
You could access all requests via the following in Global.asax file.
protected void Application_BeginRequest(Object sender, EventArgs e)
{
try {
var app = sender as HttpApplication;
var trackerId = app.Request.QueryString["trackerId"]
...do stuff...
}
catch { }
}

ASP.Net WebForms Routing Single Route for Multiple Destinations

I am looking into setting database routing up for a new website I plan to create. I have been looking at the following tutorial with regards to utilising friendlyUrls from a database:
http://www.asp.net/web-forms/tutorials/aspnet-45/getting-started-with-aspnet-45-web-forms/url-routing
However, I would like to use the same route structure for multiple entities. Meaning:
mysite.com/{PlayerName} goes to player.aspx
mysite.com/{TeamName} goes to team.aspx
… and so on …
Could somebody point in the right direction of achieving this with asp.net. Is it possible using the built in routing engine, or should I be looking to code my own HTTPModule for this?
Thanks
David
I'm not sure why so many people say that this cannot be done with routing - maybe I'm not getting something, but the same logic that apparently makes the accepted answer a valid option should be perfectly applicable to a custom route handler, e.g. IRouteHandler or something derived from System.Web.Routing.RouteBase.
You can add "managers" to your RouteCollection (RouteTable.Routes) in the manner of:
routes.Add("MyRoutName", new MyCustomRouteBaseThing())
... Or:
routes.Add(new Route("whatever/{possiblySomething}", new RouteValueDictionary {
{"whatever", null}
}, new MyImplementationOfIRouteHandler()));
... Etcetera, depending on your needs.
If you go with the RouteBase alternative for example, override GetRouteData(), GetVirtualPath() and whatnot. I'm not saying it's necessarily a better option than the accepted answer, I just don't see why routing should be deemed not viable. (What am I missing?)
EDIT: At the time I wrote the above, the "accepted answer" was the one about URL rewriting posted by Tasos K, to whom the bounty was also rewarded. The accepted answer has since been reassigned.
Write two constraints which return boolean whether segment is a team or not / a player or not.
public class IsTeamConstraint : IRouteConstraint
{
public bool Match
(
HttpContextBase httpContext,
Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection
)
{
return SomeService.IsTeam(values["teamName"]);
}
}
public class IsPlayerConstraint : IRouteConstraint
{
public bool Match
(
HttpContextBase httpContext,
Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection
)
{
return SomeService.IsPlayer(values["playerName"]);
}
}
Set constraint in page route.
void RegisterCustomRoutes(RouteCollection routes)
{
routes.MapPageRoute(
"Team",
"{teamName}",
"~/Team.aspx",
false,
null,
new RouteValueDictionary { { "isTeam", new IsTeamConstraint() } }
);
routes.MapPageRoute(
"Player",
"{playerName}",
"~/Player.aspx",
false,
null,
new RouteValueDictionary { { "isPlayer", new IsPlayerConstraint() } }
);
}
Now when a page is requested registered page routes will use constraint to check that the route is valid and execute page if it is.
I haven't tried this in ASP.Net Forms but I've applications running with constraints developed in ASP.Net MVC. Both type of application (Forms and MVC) shared common routing logic.
I also don't know how this can be done using routing. But one way to achieve this is using URL rewriting instead. The whole process has a few steps and it is rather simple to make.
Applying the URL rewriting
You add at the Global.asax the following function.
void Application_BeginRequest(object sender, EventArgs e)
{
//Here you will get exception 'Index was outside the bounds of the array' when loading home page, handle accordingly
string currentsegment = Request.Url.Segments[1];
string RewritePath = "";
if (IsTeam(currentsegment))
{
RewritePath = "~/team.aspx?team=" + currentsegment;
}
if (IsPlayer(currentsegment))
{
RewritePath = "~/player.aspx?player=" + currentsegment;
}
if (RewritePath != "") {
// Adding all query string items to the new URL
for (int I = 0; I <= Request.QueryString.Count - 1; I++)
{
RewritePath = RewritePath + "&" + Request.QueryString.Keys[I] + "=" + Request.QueryString[I];
}
Context.RewritePath(RewritePath);
}
}
So if the URL has is /some-title-here you can get the some-title-here part using the Request.Url.Segments array.
Then based on that your code detects if this title is a team or a player. In any case you change internally the URL by calling the Context.RewritePath(...).
One important thing is that you need to add all the query string items manually in order to pass them to your pages.
Also, inside your code the Request.Url will know the rewritten URL, not the original.
A quick way to test it is to implement the IsTeam(...) and IsPlayer(...) function as below. With only this code when hitting /player-tasos the ~/player.aspx?player=player-tasos page loads and when hitting /team-stackoverflow the ~/team.aspx?team=team-stackoverflow page loads.
private bool IsTeam(string segment)
{
return segment.StartsWith("team");
}
private bool IsPlayer(string segment)
{
return segment.StartsWith("player");
}
So far this approach works but it has one main issue. When there is a PostBack the URL changes to the one you have set in the Context.RewritePath(...)
Avoiding PostBack issue
To avoid this issue you need to add to your projects two ASP.NET folders
App_Browsers
App_Code
In the App_Code folder you create a file FormRewriter.cs and add the following code (In my demo the root namespace is WebFormsRewriting)
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.UI;
namespace WebFormsRewriting
{
public class FormRewriterControlAdapter : System.Web.UI.Adapters.ControlAdapter
{
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
base.Render(new RewriteFormHtmlTextWriter(writer));
}
}
public class RewriteFormHtmlTextWriter : System.Web.UI.HtmlTextWriter
{
public RewriteFormHtmlTextWriter(HtmlTextWriter writer)
: base(writer)
{
this.InnerWriter = writer.InnerWriter;
}
public RewriteFormHtmlTextWriter(System.IO.TextWriter writer)
: base(writer)
{
base.InnerWriter = writer;
}
public override void WriteAttribute(string name, string value, bool fEncode)
{
// If the attribute we are writing is the "action" attribute, and we are not on a sub-control,
// then replace the value to write with the raw URL of the request - which ensures that we'll
// preserve the PathInfo value on postback scenarios
if ((name == "action"))
{
HttpContext Context = default(HttpContext);
Context = HttpContext.Current;
if (Context.Items["ActionAlreadyWritten"] == null)
{
// Because we are using the UrlRewriting.net HttpModule, we will use the
// Request.RawUrl property within ASP.NET to retrieve the origional URL
// before it was re-written. You'll want to change the line of code below
// if you use a different URL rewriting implementation.
value = Context.Request.RawUrl;
// Indicate that we've already rewritten the <form>'s action attribute to prevent
// us from rewriting a sub-control under the <form> control
Context.Items["ActionAlreadyWritten"] = true;
}
}
base.WriteAttribute(name, value, fEncode);
}
}
}
In the App_Browsers folder you create a file Form.browser and add the following snippet. Note here to put the class name of the Adapter with its namespace.
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.HtmlControls.HtmlForm"
adapterType="WebFormsRewriting.FormRewriterControlAdapter" />
</controlAdapters>
</browser>
</browsers>
And that's it. Adding those two files will handle the PostBack issue. If you put the FormRewriter.cs outside the App_Code folder it will not work. Also those two folders must be uploaded to the production server.
I have used this approach for years in .NET 3.5 and .NET 4.0 without any problems. Today I also tested it in a .NET 4.5 Web Forms project and it works with no issues.
All of the above are based on a ScottGu's article about the subject
As others have pointed out... it would be much better NOT to use this route for both Players and Teams.
It would be preferable to setup two routes...
mysite.com/player/{PlayerName}
mysite.com/team/{TeamName}
In this way you can drive all "player" traffic to Player.aspx, and "team" traffic to Team.aspx, nice and easy.
However... If you really have to support a single route, I recommend that you add it as a third option, and use a 301 Redirect to one of the two above routes.
mysite.com/{PlayerOrTeamName} -> Route.aspx
Let Route.aspx handle requests that don't map to physical files.
Then your Route.aspx code needs to function as a 404 Error handler, but with a catch.. It will check the Players data and the Teams data for an exact match. If it finds one it should do a 301 permanent redirect to the correct /player/ or /team/ route.
Using...
string strCorrectURL = RouteTable.Routes.GetVirtualPath(null, "player", new RouteValueDictionary { { "Name", strValue }});
Response.StatusCode = 301;
Response.Status = "301 Moved Permanently";
Response.AddHeader("Location", strCorrectURL);
Response.End();
This will give you the functionality of a single path, but tell search engines to index the more precise path.
You could skip the RouteTable altogether and just put this code into your default 404 handler.

How to rewrite URL in ASP.NET 4 Web Forms and hide some parameters

I have web page in asp.net 4 Web forms, that generate this URLs:
http://www.myweb.com/Default.aspx?mode=articles&seo_name=my-best-article
and I want to show url in this format:
http://www.myweb.com/my-best-article
but i need to access original query string (mode and seo_url).
Now Im using this solution:
void RegisterRoutes(RouteCollection routes)
{
routes.MapPageRoute(
"default-page",
"{mode}/{seo_name}",
"~/Default.aspx"
);
}
but it shows both parametrs and I want only seo_name.
How can I do this?

Ajax Control Toolkit AsyncFileUploader Control and viewstate/session Issue

in my project i need to upload files so i decided to use the uploader provided by asp.net ajax controls AsyncFileUPloader control.
there are four blocks. every block contains two such uploaders
so i decided to utilize the power of asp.net web user controls.
i wrapped the required form fields in my user control called DesignUploader.ascx
now i have to put the four instances of this control on my aspx page
please refer the snap below
my problem starts here i have to insert the fileurl to the database and each of the block generates unique id and id value changes after uploading the file to the server. i noticed that viewstate does not work for me in case of asyncfileuploader it clears the viewstate because it does the secret postback to the server behind the scenes. now only option left for me is to use session but when user uploads the files in two blocks one after another then filepath from second/third consecutive blocks overwrite my session. i don't know how many blocks user can use to upload the designs he may use 1 only or he may use all four.
There would be a final submit button in the bottom of the page on click of which i have to insert data to database.
so when i tried to save the data to database the session stores the value of the recently uploaded file path for all the records my problem lies here
i don't know if i was able to describe my problem in correct manner or not please excuse me if it is not clear and post comment if required.
Note: I can not change the UI because client insists for this only :(
any quick work around would be appreciated much
Thanks
Devjosh
I believe you saving file path to session in a wrong way and it's impossible to recognize where is an error without code.
All the way, in my opinion better don't persist file path in session but use client side for that purpose instead. You can add two hidden fields to DesignUploader.ascx control and set their values in UploadedComplete event handler.
public partial class DesignUploader : System.Web.UI.UserControl
{
private static readonly string AppDataPath = HttpContext.Current.Server.MapPath("~/App_Data/");
public string FirstFilePath
{
get
{
return Server.UrlDecode( FirstFilePathHiddenField.Value);
}
}
public string SecondFilePath
{
get
{
return Server.UrlDecode(SecondFilePathHiddenField.Value);
}
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
FirstFileUpload.UploadedComplete += FirstFileUpload_UploadedComplete;
SecondileUpload.UploadedComplete += SecondileUpload_UploadedComplete;
}
void FirstFileUpload_UploadedComplete(object sender, AjaxControlToolkit.AsyncFileUploadEventArgs e)
{
var fullPath = Path.Combine(AppDataPath, Path.GetFileName(e.FileName));
FirstFileUpload.SaveAs(fullPath);
SaveFilePathToHiddenField(FirstFilePathHiddenField.ClientID, fullPath);
}
void SecondileUpload_UploadedComplete(object sender, AjaxControlToolkit.AsyncFileUploadEventArgs e)
{
var fullPath = Path.Combine(AppDataPath, Path.GetFileName(e.FileName));
SecondileUpload.SaveAs(fullPath);
SaveFilePathToHiddenField(SecondFilePathHiddenField.ClientID, fullPath);
}
private void SaveFilePathToHiddenField(string fieldId, string pathValue)
{
var script = string.Format("top.$get('{0}').value = '{1}';", fieldId, Server.UrlEncode(pathValue));
ScriptManager.RegisterStartupScript(this, this.GetType(), "setPath", script, true);
}
}

Resources