MVC4 - ContextDependentView - What does it mean? - asp.net

I have just started using MVC4 and the first action method that I look at has something new. I checked out the internet and can't find anything about this:
public ActionResult LogOn()
{
return ContextDependentView();
}
Does anyone know what a ContextDependentView is ?
Something new to me.

It's purpose is to facilitate View or PartialView action results for the Login and Register actions.
private ActionResult ContextDependentView()
{
string actionName = ControllerContext.RouteData.GetRequiredString("action");
if (Request.QueryString["content"] != null)
{
ViewBag.FormAction = "Json" + actionName;
return PartialView();
}
else
{
ViewBag.FormAction = actionName;
return View();
}
}
Like other things in MVC it is done by convention... the convention here is when the Request.QueryString contains a ?content=xxxx, it prepends "Json" to the action name, stuffs it a ViewBag property and returns the partial version of the View. For example:
A request for /Account/Login?content=test would be resolved to ViewBag.FormAction = "JsonLogin"; and then return a partial.
A request for /Account/Login has no content query string so its form action remains ViewBag.FormAction = "Login";

Related

ASP.NET MVC Remove query string in action method

I have an action method that looks like this:
public ActionResult Index(string message)
{
if (message != null)
{
ViewBag.Message = message;
}
return View();
}
What happens is that the url of a request to this will look like:
www.mysite.com/controller/?message=Hello%20world
But I want it to look just
www.mysite.com/controller/
Is there a way to remove the query string inside the actionmethod?
No, unless you use a POST method, the information has to get passed somehow. An alternative may be to use an in-between class.
// this would work if you went to controller/SetMessage?message=hello%20world
public ActionResult SetMessage(string message)
{
ViewBag.Message = message ?? "";
return RedirectToAction("Index");
}
public ActionResult Index()
{
ViewBag.Message = TempData["message"] != null ? TempData["message"] : "";
return View();
}
Or. if you simply used a POST
//your view:
#using(Html.BeginForm())
{
#Html.TextBox("message")
<input type="submit" value="submit" />
}
[HttpGet]
public ActionResult Index()
{ return View(); }
[HttpPost]
public ActionResult Index(FormCollection form)
{
ViewBag.Message = form["message"];
return View();
}
You can remove the query string by adding some JavaScript in the razor view.
#section scripts{
<script>
if (location.href.includes('?')) {
history.pushState({}, null, location.href.split('?')[0]);
}
</script>
}
If you navigate to page
www.mysite.com/controller/?message=Hello%20world
Then it'll show
www.mysite.com/controller/
in the browser.
Most modern browsers support this (browser support).
Look into routes. They define how a url with parameters will be written.
If you create a new MVC application, and look at the Global.asax.cs file under `RegisterRoutes(). you should see one entry.
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "home", action = "index", id = UrlParameter.Optional } // Parameter defaults
);
Look at each part:
"Default" is the name. This just has to be unique for each route you create.
"{controller}/{action}/{id}" is the pattern you want to use. example.org/home/index?id=2 will be written example.org/home/index/2 instead
new { controller = "home", action = "index", id = UrlParameter.Optional } is defining the defaults if nothing is specified.
So, that route make it so if you go to example.org it will assume you mean example.org/home/index{id is optional}.
Working from that, you can start to see how to create your own routes.
Now, addressing your question the short answer is yes you could make the URL look like that, but not really. You would have to define a route with a default message, and it would only look like that if someone didn't specify a message. You have to tell the controller what the message is. I'm sorry, but the best you can do is define a route that gives you
/message/Hello%20World and using string.replace make that look even nicer `'/message/hello_world'
I'm not sure you're really thinking that through. If you remove the query string... then you remove the query string.. ie, your page won't have the query string value to do whatever it needs to do.
There's a bunch of different hacks you could do.. all of them are not ideal. You could use javascript to strip out the query string. You could redirect to a querystring-less page after setting a session variable.. it's all pretty ugly.
Remember that what the user sees in the address bar is on the client. The client controls that. You can fiddle with it via javascript, but doing so is generally a bad idea. Since hiding things from the user can be considered malware-like behavior.
I recommend using a slug. Check out this post: SOF Slug post
In previous applications, I took this approach to remove querystrings from the URL.

asp mvc session variables

Need to store some auth information of client on server, to share between 2 pages.
Dont matter how, session, cookie, tempdata, i tried everything, and nothing works, for exampe:
public ActionResult CheckIn(string pass)
{
if (System.Configuration.ConfigurationManager.AppSettings["pass"] == pass)
{
HttpContext.Session.Add("admin", "yes");
}
return View();
}
public ActionResult Helper() {
if (HttpContext.Session["admin"] != null)
{
if (HttpContext.Session["admin"].ToString() == "yes")
return PartialView("InitConfig");
else
return PartialView("StationLogics");
}
else
return PartialView("StationLogics");
}
and i get always null in session in helper method. what i'm doing wrong?
Have you tried HttpContext.Current.Session instead ?
ps. doing that you do is actually not good desing you should reconsider it in your application.
Are you sure that all those if conditions are met? Try with a simple example:
public ActionResult CheckIn()
{
Session["foo"] = "bar";
return View();
}
public ActionResult Helper()
{
var foo = Session["foo"];
if (foo == null)
{
// this won't be null if you called the CheckIn method first
}
return View();
}
Call the CheckIn action first to store a value in the session and then call the Helper action. Unless you have disabled session for this ASP.NET application or cookies in your browser you should get correct value.

RedirectToAction usage in asp.net mvc

I want to post some questions about ASP.Net MVC. I am not familiar with web developing, But I was assigned to the web part of a project. We are doing the following: first, we create get & set properties for the person data:
public class Person
{
public int personID {get;set;}
public string personName {get;set;}
public string nric {get;set;}
}
and after login, we put the data in a class Person object and we use RedirectToAction like this:
return RedirectToAction("profile","person",new { personID = Person.personID});
It's working normally, but the parameter are shown in the URL. How can I hide them and also
can I hide the action name? Guide me the right way with some examples, please.
The parameter are shown in the URL because that is what the third parameter to RedirectToAction is - the route values.
The default route is {controller}/{action}/{id}
So this code:
return RedirectToAction("profile","person",new { personID = Person.personID});
Will produce the following URL/route:
/Person/Profile/123
If you want a cleaner route, like this (for example):
/people/123
Create a new route:
routes.MapRoute("PersonCleanRoute",
"people/{id}",
new {controller = "Person", action = "Profile"});
And your URL should be clean, like the above.
Alternatively, you may not like to use ID at all, you can use some other unique identifier - like a nickname.
So the URL could be like this:
people/rpm1984
To do that, just change your route:
routes.MapRoute("PersonCleanRoute",
"people/{nickname}",
new {controller = "Person", action = "Profile"});
And your action method:
public ActionResult Profile(string nickname)
{
}
And your RedirectToAction code:
return RedirectToAction("profile","person",new { nickname = Person.nickname});
Is that what your after?
If you don't want the parameter to be shown in the address bar you will need to persist it somewhere on the server between the redirects. A good place to achieve this is TempData. Here's an example:
public ActionResult Index()
{
TempData["nickname"] = Person.nickname;
return RedirectToAction("profile", "person");
}
And now on the Profile action you are redirecting to fetch it from TempData:
public ActionResult Profile()
{
var nickname = TempData["nickname"] as string;
if (nickname == null)
{
// nickname was not found in TempData.
// this usually means that the user directly
// navigated to /person/profile without passing
// through the other action which would store
// the nickname in TempData
throw new HttpException(404);
}
return View();
}
Under the covers TempData uses Session for storage but it will be automatically evicted after the redirect, so the value could be used only once which is what you need: store, redirect, fetch.
this may be solution of problem when TempData gone after refresh the page :-
when first time you get TempData in action method set it in a ViewData & write check as below:
public ActionResult Index()
{
TempData["nickname"] = Person.nickname;
return RedirectToAction("profile", "person");
}
now on the Profile action :
public ActionResult Profile()
{
var nickname = TempData["nickname"] as string;
if(nickname !=null)
ViewData["nickname"]=nickname;
if (nickname == null && ViewData["nickname"]==null)
{
throw new HttpException(404);
}
else
{
if(nickname == null)
nickname=ViewData["nickname"];
}
return View();
}
Temp data is capable of handling single subsequent request. Hence, value gone after refresh the page. To mitigate this issue, we can use Session variable also in this case. Try below:
public ActionResult Index(Person _person)
{
Session["personNickName"] = _person.nickName;
return RedirectToAction("profile", "person");
}
And in "profile" actionmethod:
public ActionResult profile()
{
Person nickName=(Person)Session["personNickName"];
if(nickName !=null)
{
//Do the logic with the nickName
}
}

Message Control in Masterpage with ASP.NET MVC

Hey everyone. Got a custom on how to do this as im new to MVC and trying to get a couple of small things implemented. This is the way I did it in WebForms but want to transition it to MVC.
I have a user control that contains CSS which will render a message. This control is located in the MasterPage and called from a ASPX page like this:
Pseudo code:
try{
Msg.MessageMode = WebPageMessageMode.OK;
Msg.ShowOK("Report deleted.");
}
catch
{
Msg.MessageMode = WebPageMessageMode.ErrorMessage;
Msg.ShowError("There was a problem deleting the report.");
}
Masterpage.aspx
<cc1:WebPageMessage runat="server" ID="msg" />
I currently have the control in the MasterPage and now im a bit confused about proceeding from here.
Should I put the 'Msg' object above from the pseudo code to a View from the MasterPage?
What is the proper way to do something like?
I dont think there is a one-solution-fits-all here.
Anyway this is my solution that uses jQuery:
1) Create a MyResultModel class to handle a message to the user
public enum MyResultType { Info, Error }
public class MyResultModel
{
public MyResultModel( MyResultType type, string message ) {
switch ( type ) {
case MyResultType.Info: Title = "OK"; break;
case MyResultType.Error: Title = "Error!!!"; break;
}
Message = message;
}
public String Title { get; set; }
public String Message { get; set; }
}
2) Create a Partial View named MyResult in the Shared Folder to handle the model
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MyResultModel>" %>
<div id="resultTitle"><%: Model.Title %></div>
<div id="resultMessage"><%: Model.Message %></div>
3) Create and use a BaseController for your controllers and add the following method to it. The method simply add a custom Http Header to the response
protected PartialViewResult PartialView( string viewName, object model, string resultHeader ) {
Response.AppendHeader( "MyHttpCustomHeader", resultHeader );
return base.PartialView( viewName, model );
}
4) In your action return a MyResultView when you've done
[HttpPost]
public virtual ActionResult DoSomething() {
try {
//Do Something
return PartialView( "MyResult",
new MyResultModel( MyResultType.Info, "Operation Completed" ),
"HttpResultInfo" );
}
catch ( Exception ex ) {
return PartialView( "MyResult",
new MyResultModel( MyResultType.Error, ex.Message ),
"HttpResultError" );
}
}
5) Finally, Submit the form using jquery and handle the results.
$.ajax({
type: "post",
dataType: "html",
url: "your/url/here",
data: $("#myform").serialize(),
success: function (response, status, xml) {
var resultType = xml.getResponseHeader("MyHttpCustomHeader");
if (resultType == null) {
//No message do whatever you need
}
else {
//response contain your HTML partial view here. Choose your
//desidered way to display it
}
}
});
With a scenario like this you dont need to place a control on the master page. You can:
Show the view as it comes from the action without any modification
Use some fancy message display technique as StackOverflow does with the orange sliding message (in this case simply extract the title and the message from the returned html)
Use some fancy jquery plugin as jGrowl to show your message
If you want to check wether it is an Info/Error message simply check the custom header with jQuery in the else branch
var title = $(response).filter("#resultTitle").text();
var message = $(response).filter("#resultMessage").text();
if (resultType == "HttpResultInfo") {
showInfoMessage(title, message);
}
else if (resultType == "HttpResultError") {
showErrorMessage(title, message);
}
Hope it helps!
In a controller, as part of the action, you can set a message like this:
public ActionResult MyAction()
{
// Do some stuff
TempData["message"] = "This is a message.";
return View("MyView");
}
In your master page or in your view:
<%
string text = TempData["Message"] as string;
Response.Write(text);
%>

ASP.NET MVC SEO URL

My goal is to have the url routing as following:
http://www.abc.com/this-is-peter-page
http://www.abc.com/this-is-john-page
What is the simplest way to achieve this without placing controller name an function name in the url above? If page above not found, I should redirect to 404 page.
Addon 1: this-is-peter-page and this-is-john-page is not static content, but is from database.
Similar to KingNestor's implementation, you can also do the followings which will ease your work:
1) Write Your Model
public class MyUser{public String UserName{get; set;}}
2) add route to global asax
routes.MapRoute(
"NameRouting",
"{name}",
new { controller = "PersonalPage", action = "Index", username="name" });
3) Roll your own custom model binder derived from IModelBinder
public class CustomBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var request = controllerContext.HttpContext.Request;
var username = getUserNameFromDashedString(request["username"]);
MyUser user = new MyUser(username);
return user;
}
}
4) in your action:
public ActionResult Index([ModelBinder(typeof(CustomBinder))] MyUser usr)
{
ViewData["Welcome"] = "Viewing " + usr.Username;
return View();
}
I personally wouldn't suggest a route like that but if it meets your needs you need to do something like:
Have the following route in your Global.asax file:
routes.MapRoute(
"NameRouting",
"{name}",
new { controller = "PersonalPage", action = "routeByName" });
Then, in your "PersonalPageController", have the following method:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult routeByName(string name)
{
switch (name)
{
case "this-is-peter-page": return View("PeterView");
case "this-is-john-page": return View("JohnView");
case Default: return View("NotFound");
}
}
Make sure you have the appropriate views: "PeterView", "JohnView" and "NotFound" in your Views/PersonalPage/.
I don't think this can be done. AFAIK ASP.NET MVC recognizes routing parameters via the character "/".
Your format, on the other hand, goes by "{controller}-is-{id}-{action}" -- so there is no way the controller can be distinguished from the id and the action.
I think using "/" characters doesn't affect or degrade SEO; it only affects human readability and retention of the URL.
Anyway, the following URL is possible: http://www.abc.com/this-is-the-page-of/Peter by adding another route in the Global.asax RegisterRoutes method:
routes.MapRoute(
"AnotherRoute",
"this-is-the-page-of/{id}",
new { controller = "PersonalPage", action = "Details", id = "" }
);
...assuming that PersonalPageController implements a Details ActionResult method that points to the desired page.

Resources