I am loading a table dynamically, and there is an unknown number of rows. Each row (each cell, actually) is loaded from the database and concatenated into a string:
tableItems+="<td colspan='8' class='reportHeaderMain borderThin'> #ViewData[\"" + tString + "Title\"]</td>";
in the code above, tString is the item number, so the title would be something like "12345Title". Later in the controller ActionResult, I assign a value to the ViewData item:
ViewData[tString + "Title"] = ((linkedArrayList)tObj[temp]).getInfo("Brand");
During breakpoints, all values store correctly, but it renders on the page as "#ViewData["..."]" instead of the ViewData value. I imagine this is because the preprocessor is doing a once-over but not a twice-over; this is to write, it is rendering the string value correctly, but not processing the resultant string (note: the markup displays correctly). This could be inherent to Mono, or it could be because, in the view, I am using HTML Raw:
#Html.Raw(#ViewData["tableItems"])
I realize it is not the best practice to generate markup in the controller like this, but this is what I am working with. Does anybody have any ideas on how to get the ViewData in the string to render as the value (e.g., brand name) rather than "ViewData[...]"? Alternative approaches are more than welcome, though (since I am new to MVC) I politely ask for details if another approach is the solution.
Thank you
I feel stupid...I would delete this question, but it might actually help fellow newbs to MVC. If anybody has a similar issue, remember where you are trying to add the value. The only place a situation like this would occur is in the controller, where you have full access to the values assigned to the ViewData. For example, if you are assigning the value of tObj to the ViewBag, then trying to load the ViewData, just concatenate with tObj. Sorry for wasting your time, guys, I learned something.
Related
I am building an MVC app that will display a bit of data at screen. I might end up having hundreds or maybe even thousands of data.
So I'm using a PagedList format following this tutorial:
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/sorting-filtering-and-paging-with-the-entity-framework-in-an-asp-net-mvc-application
Which helped me. The Paged List works. But I have one problem that I can't seem to figure out how to solve. In the tutorial, there's only 1 parameter, a textbox, and the tutorial keeps the value "in memory" by keeping and attributing the ViewBag parameter so that changing page does not "flush" the text in the textbox.
Right now I'm building something like a search engine with, right now, 23 parameters and counting. Amongst these parameters are checkboxes, textboxes, and dropdownlists.
My question: is there any way to keep these in memory? How may I proceed? Must I keep them all in memory just like the tutorial does?
Thank you very much!
Well, in the tutorial, they are not really "kept in memory" between requests. In each request, the value is passed into the action method, which then passes it to the view where it is used in creating the paging and sorting links.
Previously, when paging, instead of adding each parameter individually, I simply have a method that reads the querystring and builds the link using each provided parameter:
NameValueCollection queryString = helper.ViewContext.HttpContext.Request.QueryString;
foreach (string key in queryString)
{
if (key != null)
{
if (!newValues.ContainsKey(key))
{
if (!string.IsNullOrEmpty(queryString[key]))
{
newValues[key] = queryString[key];
}
}
}
}
Then, to create the link, I use:
string link;
if (!string.IsNullOrEmpty(routeName))
{
link = helper.RouteLink(text, routeName, newValues).ToString();
}
else
{
actionName = actionName ?? values["action"].ToString();
controllerName = controllerName ?? values["controller"].ToString();
link = helper.ActionLink(text, actionName, controllerName, newValues, null).ToString();
}
return string.Concat(" ", link);
If you are using AJAX techniques, then you can create 2 action methods in your controller.
The first should return the whole view and the second should return a partial view.
The first will contain your search controls (all 23 of them). These will be rendered only the first time.
The second one will return the partial view and will be parameterized by the 23 odd parameters you have to your search query. It might be an idea to stuff them all in a ViewModel class and let the default model binder bind it at run time.
Finally, you can then load the results part of the search results page by an AJAX call to the 2nd method using JavaScript/jQuery.
In a C# MVC3 solution I'm passing the request.form as a string to a webservice (I understand it would be much better to break it down and populate a model but it's compromised with old code and mainly with time) and at a step the string is huge due to many options and failed in the service.
Actually I won't need all of this options, which are basically several dropdownlists from which I just need one of them, so I'm trying to figure out how to change the request.form in order to remove the redundant ones and just keep the one selected.
To put this into context, this should be part of the string (just a middle chunk of it)
NG2BEF01-16344-181-E-16344-0-SHW_SHR*16344*MAT*1*2500*1600=0&NG2BEF01-16344-181-E-16344-0-SHW_SHR*16344*MAT*2*5500*6200=0&NG2BEF01-16344-181-E-16344-0-SHW_39S*16344*EVE*1*1500*0=2
And I would like to remove all of the options appart from (in this portion) the last one wich =2. This 0's and the 2 come from a dropdown list which name is all the rest of the parameter (ie NG2BEF01-16344-181-E-16344-0-SHW_39S*16344*EVE*1*1500*0) although it may be completely different, not always follow this pattern.
Is there any way I can get rid of the dropdown lists I leave to 0 in the request.form before submitting (or even in the controller would be acceptable)?
You could filter out values that you don't want to keep:
var values = HttpUtility.ParseQueryString("NG2BEF01-16344-181-E-16344-0-SHW_SHR*16344*MAT*1*2500*1600=0&NG2BEF01-16344-181-E-16344-0-SHW_SHR*16344*MAT*2*5500*6200=0&NG2BEF01-16344-181-E-16344-0-SHW_39S*16344*EVE*1*1500*0=2");
string result = string.Join("&", values.Cast<string>().Where(key => values[key] == "2").Select(key => string.Format("{0}={1}", key, HttpUtility.UrlEncode(values[key]))));
// The result variable will contain only kvps where the value equals 2
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 };
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");
}
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.