How do I use Asp MVC Url Helpers to generate RESTful links? - asp.net-mvc-routing

I'm trying to use Html.ActionLink to generate a link with in this form:
/Action/Model/Id/Parameter1/Parameter2
I've used:
<%= Html.ActionLink("Link Text", "Action", "Model", new { id = var, parament1=var1 }, null) %>
but it always ends up looking like /Action/Model/Id?parameter1=variable
I've seen similar questions on Stackoverflow and elsewhere, but I can't find a solution that works/makes sense. Any help would be appreciated.
#John: I have the following route registered: routes.MapRoute("Alternate","{controller}/{action}/{id}/{Heading}", new { controller = "Designation", action = "Details", id = "", Heading = "" }
I then have the following code in my view: <%= Html.ActionLink("Link Text", "Action", "Model", new { Id = model.Id, Heading = model.Heading }, null) %>
I get /Model/Action/Id?Heading=var1 I want it as /Model/Action/Id/var1
ANSWER: I added the following route to my global.asax.cs file and the links generated correctly.
routes.MapRoute("Something", "MyModel/MyAction/{Id}/{Heading}", new { controller = "MyModel", action = "MyAction", id = "", heading = "" }, new { controller = #"[^.]*" });

Related

GAE : How to refresh page after submitting form on GAE?

I have a form on a page and submit the details of the form on the click of the submit button and want to refresh the page after the object is added to the datastore. I read online that this could be because of the datastore's Eventual Consistency but can't seem to figure out a way to achieve the desired result(refreshing the page).
class AddUpdateProfile(webapp2.RequestHandler):
def post(self):
#This will be used to add/update profile in a datastore. Will be called when the user clicks on submit button on the Profile Page
template = JINJA_ENVIRONMENT.get_template('profile.html')
error = None
name = self.request.get('name')
designation = self.request.get('designation')
salary = self.request.get('salary')
currency = self.request.get('currency')
logging.info("Name = "+name)
logging.info("Designation = "+designation)
logging.info("Salary = "+salary)
logging.info("Currency = "+currency)
profile = UserProfile(parent=userProfile_key(users.get_current_user().email()))
profile.name = name
profile.designation = designation
profile.salary = int(salary)
profile.currency = currency
profile.email = str(users.get_current_user().email())
profile.put()
#Go back to main page. TODO : Change this to update
self.redirect('/profile')
class Profile(webapp2.RequestHandler):
def get(self):
logging.info("Inside Profile Page")
user = users.get_current_user()
if user:
profileInfo = getProfileInformation(user.email())
logging.info("Found a user inside Profile Page")
url = users.create_logout_url(self.request.uri)
if profileInfo is None or not profileInfo:
logging.info("Email = "+user.email())
logging.info("Profile Info not found")
template_values = {
'user': user.nickname(),
'url': url
}
else:
logging.info("Profile Info found")
template_values = {
'user': user.nickname(),
'url': url,
'name' : profileInfo[0].name,
'designation' : profileInfo[0].designation,
'salary' : profileInfo[0].salary,
'currency' : profileInfo[0].currency
}
template_values = template_values
template = JINJA_ENVIRONMENT.get_template('profile.html')
self.response.write(template.render(template_values))
else:
logging.info("User not found. Loading Landing page")
template_values = {
'url' : users.create_login_url(self.request.uri)
}
template = JINJA_ENVIRONMENT.get_template('landing.html')
self.response.write(template.render(template_values))
class MainPage(webapp2.RequestHandler):
def get(self):
logging.info("Inside MainPage")
user = users.get_current_user()
if user:
logging.info("Found a user inside MainPage")
url = users.create_logout_url(self.request.uri)
url_linktext = 'SIGN OUT'
template_values = {
'user': user.nickname(),
'url': url,
'userPage' : "no",
'url_linktext': url_linktext,
}
template = JINJA_ENVIRONMENT.get_template('index.html')
self.response.write(template.render(template_values))
else:
logging.info("User not found. Loading Landing page")
template_values = {
'url' : users.create_login_url(self.request.uri)
}
template = JINJA_ENVIRONMENT.get_template('landing.html')
self.response.write(template.render(template_values))
app = webapp2.WSGIApplication([
('/', MainPage),
('/profile', Profile),
('/addProfile', AddUpdateProfile)
], debug=True)
It would be great if someone could have a look at the code and give me some input on how to resolve the issue.
Any help is really appreciated!
Thanks!
Not sure if this is what you are looking for, but in general, if you want to refresh the page, you should do it using Javascript/JQuery on your page.
Have your endpoint send back a JSON response back to the '/profile'. The response should look something like:
{"success":"success"}
Or if, you need to send an error message:
{"error": "insert error message here"}
Your Javascript and/JQuery should then check if "error" is in the response. If it is throw an error message, otherwise, refresh the page.
How to reload a page using Javascript?

MVC2 Custom Routing Breaks when site is located in IIS sub folder

So, I have implemented custom routing in mysite.
routes.MapRoute(
"WithFriendlyNameOnly",
"{friendlyName}",
new { controller = "Home", action = "Redirect", friendlyName = String.Empty, id = UrlParameter.Optional },
new { friendlyName = new MustBeFriendlyName() }
);
routes.MapRoute(
"WithFriendlyNameDefault",
"{friendlyName}/{controller}",
new { controller = "Home", action = "Index", friendlyName = String.Empty, id = UrlParameter.Optional },
new { friendlyName = new MustBeFriendlyName() }
);
routes.MapRoute(
"WithFriendlyName",
"{friendlyName}/{controller}/{action}/{id}",
new { controller = "Home", action = "Redirect", friendlyName = String.Empty, id = UrlParameter.Optional },
new { friendlyName = new MustBeFriendlyName() }
);
routes.MapRoute(
"DefaultWithRule", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { controller = new MustNotRequireFriendlyName() }
);
This works fine locally. I am using the friendly name to determine your context in site site. Without it, all I give you is a 404 page.
My test environment is a Windows 2008 Server (IIS 7.5), and my application is in a subfolder like this: test.mydomain.com/mysite. Everything worked fine until I did this new custom url, so I'm fairly sure it isn't IIS or the server. However, my custom routes are not working at all. My regular routes are working just fine - like the home page, some information pages etc. It is only the pages with my custom routing. What did I do wrong?
Have you tried to switch routes order making more specific at the beginning? It worked for me.
Try also that debugger: http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx
Helps very much!

jquery ui autocomplete js error on keydown

i've included the jquery ui automcomplete plugin into the following structure:
<li class="search">
<input type="text" class="searchfield" name="searchfield" value="Search for Products" />
</li>
my javascript for this input field looks like:
<script type="text/javascript">
function addSearchFieldFunctionality() {
var availableTags = [
"ActionScript",
"AppleScript",
"Asp",
"BASIC",
"C",
"C++",
"Clojure",
"COBOL",
"ColdFusion",
"Erlang",
"Fortran",
"Groovy",
"Haskell",
"Java",
"JavaScript",
"Lisp",
"Perl",
"PHP",
"Python",
"Ruby",
"Scala",
"Scheme"
];
$('.searchfield').each(function () {
$(this).autocomplete({
source: availableTags,
minLength: 1
}).data("autocomplete")._renderItem = function(ul, item) {
//console.log(item);
var a = $('<a>', {
href: item.value,
text: item.label,
"class" : "mySearchClass"
});
var b = $('<a>', {
href: item.value,
text: "Add", style: "float:right"});
var $li = $('<li></li>', {style:"width:100%"});
return $li.add(a).appendTo(ul);
};
});
}
</script>
I'm loading that function on document ready. for some reason, if a start typing e.g. the first three letters of a item, i get a resultlist. as soon as i push the keydown push button on the keyword, i get the following error in the chrome (latest version) console:
Uncaught TypeError: Cannot read property 'top' of null
a.widget.activate jquery-ui.min.js:12
a.widget.move jquery-ui.min.js:12
a.widget.next jquery-ui.min.js:12
a.widget._move jquery-ui.min.js:12
a.widget._create.element.addClass.attr.attr.bind.bind.d jquery-ui.min.js:12
f.event.dispatch jquery-1.7.1.min.js:3
f.event.add.h.handle.i
i'm using version 1.7.1 of jQuery and Version 1.8.12 of jquery UI
On the demo page of jquery ui autocomplete the keydown works well.
Any ideas what's going wrong with my constellation?
It doesn't make a difference to use remote or local data.
Best regards,
Ramo
I really can make your code working. So I tried to rewrote it in a more simplier way. The problem is render functions only accept strings, not html element. So I add a listener to render the list after its generation (fired on keydown() event).
My thought is you are doing it the wrong way.
why adding another class on those items ? they have already one, so they can be styled.
why transforming them into a nodes ? just add a click() event on them
Could you explain your functional goal ?
// Your list of links
var redirectLinks = {'Ruby': '1234.com', 'Asp': '1235.com'};
function redirect(url) {
// TODO implement window.location=url or whatever you like
if(redirectLinks[url] != undefined) {
alert('redirecting to '+url+' => '+redirectLinks[url]);
}
}
$('.searchfield').each(function () {
$(this).autocomplete(availableTags, {
minLength: 1,
change: function(event, ui) {
console.log('this change event doesnt seem to be fired');
},
select: function(event, ui) {
console.log('this select event doesnt seem to be fired');
}
});
// After the list construction
$(this).keyup(function(e){
if (e.which == 13) { // typing enter validates the input => autocompletechange
console.log('validating input '+$(this).val());
redirect($(this).val());
}
var $list = $('.ac_results:first ul').find('li');
$list.click(function() { // adding an event on suggestion => autocompleteselect
console.log('clicking on suggestion '+$(this).text());
redirect($(this).text());
});
});
});

MVC2 - Route mapped but QueryString rendered

in my Asp.net MVC2 app I have registered the following routes in the global.asax.cs:
routes.MapRoute(
"Search",
"Search/{action}/{category}/{query}/{page}",
new { controller = "Search", action = "Results", category = "All", page = 1 },
new { page = #"\d{1,8}" }
);
// URL: /Search
routes.MapRoute(
"SearchDefault",
"Search",
new { controller = "Search", action="Index" }
);
routes.MapRoute(
"Product",
"Product/{action}/{productcode}",
new { controller = "Product", action = "Details" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Search", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
I have my SearchController:
public ActionResult Results(string category, string query, int page)
{
}
I have my ProductController:
public ActionResult Details(string productcode)
{
return View();
}
In my Results.aspx View, the following ActionLinks exist:
<% foreach (var cat in Model.Categories) { %>
<li><%= Html.ActionLink(cat.Name, "Results", "Search", new { category= cat.Name, query = Model.SearchText, page=1 }, null)%></li>
<% } %>
</ul>
<hr />
<table>
<% foreach (var p in Model.Products) { %>
<tr>
<td>
<%= Html.ActionLink(p.ProductName, "Details", "Product", new { product = p.ProductCode }, new { })%><br />
</td>
</tr>
<% } %>
The first actionlink is rendering as:
"http://localhost/Search/Results?category=Test%20Category%20A&query=test%20product&page=1"
whereas the second ActionLink is correctly rendering:
"http://localhost/Product/Details/1234ABC020848"
The strange thing is that both work correctly and even if I manually type in:
"http://localhost/Search/Results/Test%20Category%20A/test%20product/1"
then my SearchController correctly executes also. I really would rather have the cleaner URL rendered by my ActionLink. What have I missed?
Thanks in advance.
As I donĀ“t have your model, I did remove the foreach loops and I replace all unknown values by strings. In my tests I found the opposite behavior: the first link was ok while the other was not cleaner. The fix for the second action link was to replace "product" by "productcode".
<ul>
<li><%= Html.ActionLink("Category", "Results", "Search", new { category= "Test Category A", query = "test product", page=2 }, null)%></li>
</ul>
<hr />
<table>
<tr>
<td>
<%= Html.ActionLink("Product", "Details", "Product", new { productcode = "1234ABC020848" }, new { })%><br />
</td>
</tr>
</table>
Both ways are suppose to work as the routing system is responsible for mapping the variables.
routes.MapRoute(
"SearchDefault",
"{controller}/{action}/{category}/{query}/{page}",
new { },
new { controller = "Search", action = "Results" }
);
This should get you url like this (some additional tweaks may be required)
http://localhost/Search/Results/Test%20Category%20A/test%20product/1
Ignore that... I didn't see the first route in the question.
I usually like to use query string for searches tho, because once you got two or more parameters that aren't required, routes for that are kinda pain to build and maintain.

ActionLink in Asp.Net Mvc 2 does not reidrect

I have the following default and only route:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
In my Site.Master I have the following:
<%= Html.ActionLink("Profile", "Details", "Users")%>
If I am on the following Url:
http://localhost:1155/Users/Details/1
and I click the link above it goes the same page.
Should it not go to the following url?
http://localhost:1155/Users/Details
For some reason it is keeping the id in the Url.
For some reason it is keeping the id in the Url.
It is by design.
Try this to get rid of id:
<%= Html.ActionLink("Profile", "Details", "Users", new { id = "" }, null)%>