Routing - Explanation for 404 page - c#

I use asp.net 4, c# and Routing for my web site.
My Route result like
A) http://mysite.com/article/58/mytitle (result my article all is fine)
58 and mytitle represent in Id and Title Column in DataBase for my Articles table.
I notice that... if I request:
http://mysite.com/article/2000000000/mytitle (a not existing ID)
I receive an Error page.
If instead I try:
B) http://mysite.com/article/58/mytitttttttle (title misspelled)
I still get my page http://mysite.com/article/58/mytitle
I would need to have my website redirect to a 404 page if both the ID or the TITLE do not not represent any record in my DataSource.
PS: I notice that SO website has a similar behavior, apart that they are able to redirect to a 404 page if the ID for a questions does not match.
My questions:
is this a normal behavior?
how to redirect to 404 pages instead?
if is not possible to use 404 pages would make use canonical urls?
I asked because I'm concerning on this scenario, lets imagine a website link wrongly to my site like
http://mysite.com/article/58/mytitttttttle (title misspelled)
or
http://mysite.com/article/58/mytitttttttle2222 (title misspelled)
both will be index my Search Engine and resulting in duplicate content (and it is not good).
Please provide me a sample of code if possible. I appreciate your comment on this, thanks!

The reason this happens is because it uses the numerical id as the search key (in this case it looks for post 58 no matter what).
What you could do is either
get rid of numerical id, and stick with just text OR
retrieve the post, and verify the "postslug" is correct based on what you pulled out from database.
By using just text, you get a cleaner url. However you have to rely on your database indexing your strings in order to have high performance lookup on your postslug. And you have to worry about duplicate slugs.
By using the hybrid, you have less clean url (extra info), but you don't need to worry too much about integer lookup performance.
Which ever choice you pick, you verify this information in your controller, then either return View, or return HttpNotFound()

Hi I did this recently and used this blog which helped alot
http://weblogs.asp.net/paxer/archive/2010/05/31/asp-net-http-404-and-seo.aspx
http://searchengineland.com/url-rewriting-custom-error-pages-in-aspnet-20-12234

Rather than passing the ID and Title, I would recommend saving the Title as a unique value in the database so you can just have:
http://mysite.com/article/title
What happens if there are two titles? Well, then you can create a loop until you find a unique one incrementing an integer at the end like:
http://mysite.com/article/title-2
This gets around the issue of their being an ~infinite number of possible URLs which all point to the same page (which Google will hate you for)
Alternatively, if you wish to keep your URL with both the ID and Title in place, then on your web form run an if statement which returns how many records in the database match the variables.
Something like:
cmd.CommandText = "SELECT COUNT(*) FROM Table WHERE ID=#ID AND Title=#Title"
if ((int)cmd.executescalar == 0){
Response.Redirect("404.aspx");
}

Related

I would like to clear my querystring after using it on page load c#

Before I ask this question, I'm not even sure what I'm using is a query string (I'm so clueless on this, what I have is the result of some other confusing StackOverFlow research). It is a parameter I'm passing from my SSRS report viewer to my app via a hyperlink expression. It works and everything is grand except for I'd like to clear it from the url right afterwards.
http://10.155.54.101/Update?CurrencyId=67
And I am getting the parameter with this logic on page load.
if (Request.Params["CurrencyId"] != null)
int CurrencyId = int.parse(Request.Params["CurrencyId"]);
I am successfully capturing that information and populating asp.net controls with it but I want to clear it from the address bar now as it lingers after submitting the update (postback?).
Through another Stack Overflow Answer: Clear QueryString on PostBack , I've attempted to clear the querystring through the following code.
Request.Params.Clear();
But I get a collection is read-only error, which is addressed in the stack overflow question above. So I try to use System.Reflection to change the read only property of the collection with the following code.
PropertyInfo Isreadonly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
Isreadonly.SetValue(Request.Params, false, null);
Request.Params.Clear();
I don't get the error but nothing is removed, so I might not be referencing the querystring properly because of however the heck Request.Params works.
Can someone nudge me in the right direction with this? I'm so sorry I'm clueless as heck on this.
You can't just change the URL in the address bar of a browser. You could redirect the browser to the URL without the query string, but seeing how you are using the value to populate controls on the page being render that would mean you would need to still need to have that value.
When you say "it lingers after submitting the update", do you mean the user chooses the currency and is redirected to the the page with this query string? If so could you change this action to a POST instead of a GET? Then you could put the currencyId in the body of the POST. If you can't switch it to a POST, then there are a few ideas I listed below.
If you are using session, you could store the currencyId in the user's session. But that would only make sense if you needed to use this value on other requests; as using session is a big decision and if you can keep your website stateless you should.
With that being said, there are two viable options to keep your site stateless. If you need this value on future requests, you can store it in a cookie. If you only need it on this request, you could have the page do post to the URL without the query string but with the value in the POST body.

Error when trying to create/update a custom form

I've been assigned to work on a project that uses the AtTask API to create an issue and accompanying custom form from a web application I've built for our intranet. I've been using this post, ATTask API - Updating Custom Field with API and C Sharp, as my main starting reference for accomplishing my task.
Like that post, I'm also getting (500) Internal Server Error, though the error I receive the URL is inserted directly into the browser is {"error":{"class":"com.attask.util.json.JSONException","message":"org.codehaus.jackson.JsonParseException: Unexpected character ('S' (code 83)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')\n at [Source: java.io.StringReader#45c828e1; line: 1, column: 6]"}}.
My URL looks like this:
https://myCo.attasksandbox.com/attask/api/v3.0/optask?method=put&projectID=myID&name=API%20SandBox%20Issue&updates={DE:Service%20Affected:Electronic%20Communications,DE:Technical%20Details:I%20dunno,DE:How%20will%20this%20change%20be%20communicated?:It%20wont}&username=myUserName&password=myPassword
I have noticed that one difference between the post I reference above and my URL is that the other post's URL is looking for a categoryID. Is that necessary for working with Custom Forms? If so, where do I find that ID? (I did a search query on an issue that had custom form of the kind I'm trying to generate, but no categoryID was returned).
By the way, my search query looks like this:
Console.WriteLine("**Searching for Change Management Issues");
JToken cmIssues = client.Search(ObjCode.ISSUE, new
{
projectID=cmProjID,
name="SandBox Issue",
name_Mod="contains",
fields="parameterValues"
});
foreach (JToken issue in cmIssues["data"].Children())
{
Console.WriteLine(issue["name"]);
Console.WriteLine(issue["categoryID"]);
Console.WriteLine(issue);
}
I've used both ISSUE & OPTASK ObjCode types, with no luck on the categoryID.
Try removing the sessionID. At the end you are using your username & password, you do not need both. Make sure you spell password correctly. In your example you spelled it wrong.
If that does not work. Make sure all the spaces are replaced with %20 by UrlEncode it before you send the call.
After finally being able to come back to this project, I found that my problems lay with my unfamiliarity with JSON calls. For this particular issue, (after the I fixed the spelling of password), I was receiving my error because I had surrounded neither the custom form object I was sending nor the related value in quotation marks.
Basically, my problem was that I was doing this:
DE:The Object:The Value
when I should have been doing this:
"DE:The Object":"The Value"

Sitecore WFFM check duplicate email

I am developing a form validation action for WFFM, which will not allow people to use same email for submitting multiple entries. So far, the only document I've got is the WFFM v2.3 Ref from Sitecore SDN, which only have few example of how to access submitted data form by form.
I don't know how to select data by using field value. So, my current solution is to retrieve all data from database and check all email fields; which doesn't seem right when putting in scale.
Do you have any code snippet that can help me add GridFilter like email="abc#def.com", if count > 0 definitely the email is duplicated?
Thank you.
Instead of finding the API supporting this very own demand, I found it easier to make a direct connection to the WFFM database and look up for what I want. Thank you for reading this.
The webforms database has 3 tables only. If for example, you want the list of email ids available in the 'Support Form' below:
Here's the query:
SELECT DISTINCT Value FROM [dbo].[Field]
WHERE FieldId = '5F5643B6-0535-49D8-B3C9-CF8E65A415C0'
Field Id corresponds to the field GUID of the form:
Ps. WebForms connections string should be available in App_Config\Include\forms.config.

Passing parameters to Controller ..but NOT on the URL

Is there a way to pass a parameter to a controller without putting it on the URL?
For example,
http://www.winepassionate.com/p/19/wine-chianti-docg-la-moto
has the value 19 on the URL. If you actually change that value to another, the page displays a different record even it the page name remains the same.
So I would like to NOT pass the ID on the URL but still be able to pass that to the Controller.
What's the recommended way to do so?
You can do a post and send it as a form parameter. I do not recommend this. Posts should be for requests that modify data. In this case you're most likely looking just to get that data. The fact that the id is in the URL is a good thing (see the Stack Overflow URLs for reference). If you really don't want the user to be able to modify it (I hope it's not because you think this makes it more secure, because it doesn't), you could do some simple encryption on it to make it more difficult to guess/produce a valid ID.
Using TempData, as some other suggest, is not a robust solution. It won't work for links on a page, just a GET after POST, and then only once since TempData is deleted after the next request.
Well, you have a couple of options:
Is this a form post? If so, then you can simply add a specific key value pair to your form when you submit it and then data will be passed along.
Is the URL unique to that resource? i.e. Does "Wine-chianti-docg-la-moto" exist as a unique representation of the number 19 in a database somewhere? If so, then you can simply do a lookup of that route component in your database to retrieve the value you need (or push that logic all the way down to the database).
Is that a value that is not expected to change a bunch? You can set that value in Session or in a cookie that would be persisted across pages and then pull it from the respective collection.
Are you redirecting to this page from another request on your server? If so, then you can use TempData to store this temporary value. However, I would recommend against this approach, as it is very transient and not good practice imo.
Lastly, you can obscure the value on the URL if you dont want it to be easily user editable. Encrypt it with some algorithm, and then decrypt it on the destination page. The user will be unlikely to be able to alter the ID by typing in a different value in the URL.
If the page is a GET, and you are following the PRG like you should be (Post-Redirect-Get) then you can use TempData["dataName"] = value; in your [HttpPost] controller and then consume it in your [HttpGet] method. It really depends on how the page is being called.
However, there is nothing wrong in letting the user change that number if it is not security related, and is common practice to show non-vital information in the url like that.
You should use TempData in this case. A good read on this can be found on this blog.
TempData allows you to store a value temporarily between requests and is, by default, erased after being accessed.
// TempData samplepublic ActionResult Featured(){ var featuredProduct = new Product { Name = "Assorted Cupcakes", Description = "Delectable vanilla and chocolate cupcakes", CreationDate = DateTime.Today, ExpirationDate = DateTime.Today.AddDays(7), ImageName = "cupcakes.jpg", Price = 5.99M, QtyOnHand = 12 };

Getting more than one item from a database in ASP .NET MVC 3

I'm creating a database where users can enter some Error Reports and we can view them. I'm making these database with C# in the ASP MVC 3 .NET framework (as the tags imply). Each Error Report has a unique ID, dubbed ReportId, thus none of them are stored under the same Id. However, whenever a User creates a new Error, I pass their User Name and store it in with the rest of the report (I use User.Identity.Name.ToString() to get their name and store it as a string). I know how to get a single item from the data using a lambda expression, like so:
db.DBSetName.Single(g => g.Name == genre)
The above code is based on an MVC 3 tutorial (The Movie Store one) provided by ASP. This was how they taught me how to do it.
My major question is: is there a member function like the .Single one that will parse through the whole database and only output database entries whose stored User Name matches that of the currently logged in user's? Then, I can use this to restrict User's to being only able to edit their own entries, since only their entries would be passed to the User's View.
What would be the best way to implement this? Since the ReportId will not be changed, a new data structure can be created to store the user's Errors and passed through to the Index (or Home) View of that particular controller. From there they should be able to click any edit link, which will pass the stored ReportId back to the Edit Action of this particular controller, which can then search the entire database for it. Am I right in assuming this would work? And would this be ideal, given that the other items in the database are NOT passed through to the Index in this method, meaning the User does not have access to the other items' ReportId's, which the user needs to pass into the Edit Action for it to work? If this is ideal, this is the method that requires me to know how to parse through a database and grab every element that fits a particular description (stored User Name matches User's current User Name).
Or would a better approach be to pass the whole database to the Index View and only output the database entries that have User Name values that match the current logged in user's? I guess this could be done in a foreach loop with a nested if loop, like so:
#foreach(var item in db.Reports)
{
if(item.UserName == User.Identity.Name.ToString())
{
...code to output table...
}
}
But this passes the whole database which gives the user a lot more info than they need. It also gives them potential access to info I don't want them to have. However, I don't have to make a new data structure or database, which should lower server memory usage and fetch time, right? Or are databases passed by copy? If so, this method seems kinda dumb. However, I don't know if the first method would fracture the database potentially, this one certainly would not. Also don't remember if I NEED an else statement in C#, I'm more familiar with C++, where you don't need one and you also don't need {}'s for single line if's, if I need one: please don't judge me too harshly on it!
Small note: I am using CRUD Controllers made with the Entity First Framework in order to edit my database. As such, all creation, reading, updating, and deletion code has been provided for me. I have chosen not to add such basic, common code. If it is needed, I can add it. I will add what the Edit Action looks like:
public ActionResult Edit(string id)
{
Report report = db.Reports.Find(id);
return View(report);
}
It accepts a string as an id, ReportId is the id used and it IS a string. It is a randomly generated GUID string made with the GUID.NewGuid().ToString() function. I will also be doing the comparison of names with:
Model.UserName == User.Identity.Name.ToString()
Which was shown earlier. Sorry if this is too much text, I wanted to provide as much info as possible and not make anyone mad. If more info is needed, it can certainly be provided. So at the end of the post, the major question actually comes down to: which of the above two methods is best? And, if it's the first one, how do I implement something like that?
Thanks for your help!
Unless I'm completely misunderstanding you, you just want .Where()
Like this:
var reports = db.Reports.Where(r => r.genre == inputGenre);
This would get you an IEnumerable of Report, which you could then use however you wish.

Categories