View is sending null value to the controller - c#

I have a view file from where I am trying to send the url to the controller file
My view file looks like:
#model WebRole1.Models.CodeSnippet
#{
ViewBag.Title = "Details";
}
<p>
#Html.ActionLink("Preview", "Preview", new { Model.URL }) |
</p>
In the above code I am trying to send the url value to the controller file. Function in the controller file looks like
public ActionResult Preview(object zipPath)
{
// some operation...
}
However for some reason view is sending null value to the controller. i.e. when Preview method of controller gets called zipPath value remains null. What can be the issue?

Your action method is waiting for property with the name zipPath. But, since you don't provide a name for a property in your anonymous object, it will be URL by default.
So, change your code to:
#Html.ActionLink("Preview", "Preview", new { zipPath = Model.URL })
Additional information:
If you have included zipPath as a URL segment in your route, then the value will assigned to this segment by the routing segment. Otherwise, the value we supplied will be added as part of the query string.

Related

Execute a controller from view in ASP.NET MVC - Razor

I am trying to print the name of the user who executes my web app. It is written in MVC-Razor.
From the initial View, I would to execute the controller below:
[Authorize]
public ActionResult Check()
{
var check = new CheckAD();
var user = new User {Name = check.CheckSecurityWithAD()};
if (!string.IsNullOrEmpty(user.Name))
{
return View("Checked", user);
}
var errors = new ErrorsModel()
{
Messages = new List<string>(){"You don't have permission"}
};
return View("Error", errors);
}
This controller returns another view if the user is correctly authenticated:
#model UsersActivationWeb.Models.User
#{
ViewBag.Title = "Checked";
}
#{ <p> Logged come #Model.Name </p>};
How can I print the second view (I think it's a partial view) in the first one using the controller?
Thanks
Sounds to me like you need an Html.Action. This will run the controller code and display the view contents that are produced where you place the call.
Most likely you will need this overload, Html.Action(string actionName, string controllerName).
Assuming the controller is called CheckController. In your initial view call it like this
#Html.Action("Check","Check")
Since you don't want people navigating to the Check view you should give it a ChildActionOnly attribute so it looks like this
[Authorize]
[ChildActionOnly]
public ActionResult Check()
{
//rest of code
}
Finally you almost certainly don't want the layout contents to appear with the Checked view so change your Checked view to this
#model UsersActivationWeb.Models.User
#{
Layout = null;
}
#{ <p> Logged come #Model.Name </p>};
Since you are doing authorization logic in the Check action you might not need the Authorize attribute. I say that because with it a user not logged in will not get the error or their name. Maybe you want this though, I'd need to know more about your code to say for sure.
This way you will either get the name of the user or the errors as required.

ASP.NET: Saving and displaying value passed from URL

I have passed a string value farmName from one controller to another.
<a asp-action="Index" asp-controller="JFTreatment" asp-route-farmName="#item.Farm.Name">link</a>
I can see in my index view that it has been passed successfully:
I would now like to display the farmName as a title in my edit view, but I am unsure of the syntax of how to set a session string or how to display it.
Assuming that you're setting your Title using ViewData["Title"] dictionary that is set on every page. You can do the following to get the farmName from Url.
Option 1: Get the query value directly from Query Collection
foreach(var query in HttpContext.Request.Query)
{
if(query.Key == "farmName")
{
ViewData["Title"] = query.Value;
}
}
Option 2: Get your route data as method parameter (Recommended)
For this option to work, your Index method should look like this:
public IActionResult Index(string farmName, int? plotId = null){
ViewData["Title"] = farmName;
... Some more code
}
Here the route property is received via Action Parameter...
Figured it out!
I did it using session string
I received the URL through
public async Task<IActionResult> Index( string farmName){
HttpContext.Session.SetString("farmName", farmName);}
Then just set add the reference
#using Microsoft.AspNetCore.Http
Then set the title with
ViewData["Title"] = #Context.Session.GetString("farmName");

ViewDataDictionary vs anonymous object in ASP.net MVC 5

I am a beginner and I am going through some tutorials in my MVC. So, I came across two scenarios.
Scenario 1.
I had to pass some data to my view on post and then send that data as hidden field. Here is the code.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ForgotPassword(ForgotPasswordMV viewModel)
{
if (ModelState.IsValid)
{
return RedirectToAction("VerifyToken", new { emailId = viewModel.EmailId });
}
^^ USING ANONYMOUS OBJECTS
return View();
}
public ActionResult VerifyToken(string emailId = null)
{
VerifyTokenMV viewModel = new VerifyTokenMV
{
EmailId = emailId
};
return View(viewModel);
}
VerifyToken View
#using (#Html.BeginForm("VerifyToken", "Security"))
{
#Html.HiddenFor(m => m.EmailId)
<button class="btn btn-primary">Continue</button>
}
Works Perfectly fine. I am able to receive values of EmailId. So far so good.
Scenario 2.
Needed to open a partial view from Main view, here is the snippet.
Main cshtml file
<div class="abc">
#Html.Partial("../Widget/Customize", Model.Unit, new ViewDataDictionary() { { "ElementName", "UnitWidget" } })
</div>
partial cshtml file
#{
string custWidgetElementName = ViewBag.ElementName;
}
// some html code below
Observation:
In scenario 2 why have I used ViewDataDictionary. Although both example works perfectly fine. But is there any reason that I had to use ViewDataDictionary. In scenraio 1 can we use ViewDataDictionary? If Yes, then which one is optimum solution.
Question: When I need to pass values shall I use new {key : value} or use ViewDataDictionary or there is no corelation? Instead of ViewDataDictionary can I use anonymous object in Senario 2
Your two scenarios are totally different. They are not doing the same thing.
In scenario 1 when using this line:
return RedirectToAction("VerifyToken", new { emailId = viewModel.EmailId });
A new URL is genrated and sent back to the client (the browser) with HTTP Code 301 or 302. When received the browser will re-contact your application wiht the received URL. With that URL, your application will execute the associated action. In your case, the client's browser will call VerifyToken action with the emailId parameter setted when you call RedirectionToAction into ForgotPassword action. So using RedirectionToAction method is just telling that method to generate a new URL with parameter defined in the anonymous type.
In scenario 2 is completely different to scenario 1. With this line:
#Html.Partial("../Widget/Customize", Model.Unit, new ViewDataDictionary() { { "ElementName", "UnitWidget" } })
You're telling your view to inject the partial view which path is ../Widget/Customize. Because that partial view the strongly typed, you passed Model.Unit as an second parameter. You use also a third parameter new ViewDataDictionary() { { "ElementName", "UnitWidget" } } because your partial seems to internally need to access to the dynamic property ViewBag or dictionary property ViewData of your view.
Conclusion:
In scenario 1 you are just telling the client's browser to go to the new URL you have generated after requesting ForgetPassword URL. We just call that a rediretion.
In scenario 2, you're just rendering a partial view into a view. The client's broswer doesn't know anything what's going on with partial views they don't know if they exist.

how i can bind data to model with post method asp.mvc [duplicate]

I want to send a message to userID=3 by going to /MyController/Message/3
This executes Message() [get] action, I enter some text in the text area and click on Save to post the form
Message() [post] action saves the changes, resets the value of SomeText to empty string and returns to the view.
At this point I expect the text area to be empty because I have set ViewData["SomeText"] to string.Empty.
Why is text area value not updated to empty string after post action?
Here are the actions:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Message(int ID)
{
ViewData["ID"] = ID;
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Message(int ID, string SomeText)
{
// save Text to database
SaveToDB(ID, SomeText);
// set the value of SomeText to empty and return to view
ViewData["SomeText"] = string.Empty;
return View();
}
And the corresponding view:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<% using (Html.BeginForm())
{ %>
<%= Html.Hidden("ID", ViewData["ID"])%>
<label for="SomeText">SomeText:</label>
<%= Html.TextArea("SomeText", ViewData["SomeText"]) %>
<input type="submit" value="Save" />
<% } %>
</asp:Content>
The problem is that your ModelState is re-filled with the posted values.
What you can do is clear it on the Action that has the Post attribute :
ModelState.Clear();
The problem is the HtmlHelper is retrieving the ModelState value, which is filled with the posted data. Rather than hacking round this by resetting the ModelState, why not redirect back to the [get] action. The [post] action could also set a temporary status message like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Message(int ID, string SomeText)
{
// save Text to database
SaveToDB(ID, SomeText);
TempData["message"] = "Message sent";
return RedirectToAction("Message");
}
This seems to me like more correct behaviour.
The html helpers read the value from the ModelState. And there's no elegant way to override this behaviour.
But if you add this line after SaveToDB(ID, SomeText), it should work :
ModelState["SomeText"].Value =
new ValueProviderResult("", "", CultureInfo.CurrentCulture);
I tried everything, but only worked when I did something like this:
ModelState.Clear();
//This will clear the address that was submited
viewModel.Address = new Address();
viewModel.Message = "Dados salvos com sucesso!";
return View("Addresses", ReturnViewModel(viewModel));
Hope this helps.
Instead of using ModelState.Clear() which clears the whole modelstate, you can do ModelState.Remove("SomeText"), if you want to. Or render the Input without the htmlhelper-extensions.
They are designed to take the Value from ModelState instead of the Model (or viewdata).
That is a clientside behavior. I would recommend using javascript. If you use JQuery, you can do it like this:
<script type="text/javascript">
$(function(){ $("#SomeText").val("");});
</script>
I don't use Javascript anymore, but I believe in regular JS that it is like:
document.getElementById("SomeText").value = "";
(You would do this on one of the load events.
<body onload="...">
Hope this helps.
I am fairly certain the textarea is grabbing the value from the Request.Form under the hood since ViewData["SomeText"] is empty.
Is it possible that the model state has been updated with an error? I believe that it will pull the attempted value from the model state rather than from view data or the model if the model state isn't valid.
EDIT:
I'm including the relevant section of the source code from the TextArea HtmlHelper extension below. It appears to me that it does exactly what I expected -- if there has been a model error, it pulls the value from the model state, otherwise it uses it from ViewData. Note that in your Post method the "SomeText" key shouldn't even exist until you set it, i.e., it won't be carried forward from the version of the code that responds to the GET.
Since you explicitly supply a value to the ViewData, useViewData should be false, attemptedValue should be false unless an error has been set in the model state.
// If there are any errors for a named field, we add the css attribute.
ModelState modelState;
if (htmlHelper.ViewData.ModelState.TryGetValue(name, out modelState)) {
if (modelState.Errors.Count > 0) {
tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
}
}
// The first newline is always trimmed when a TextArea is rendered, so we add an extra one
// in case the value being rendered is something like "\r\nHello".
// The attempted value receives precedence over the explicitly supplied value parameter.
string attemptedValue = (string)htmlHelper.GetModelStateValue(name, typeof(string));
tagBuilder.SetInnerText(Environment.NewLine + (attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(name) : value)));
return tagBuilder.ToString(TagRenderMode.Normal);
Do s.th. like this:
add:
ModelState.Clear();
before the return statement of the submit buttons action method. Works for me. It could work for you.

Reset the value of textarea after form submission

I want to send a message to userID=3 by going to /MyController/Message/3
This executes Message() [get] action, I enter some text in the text area and click on Save to post the form
Message() [post] action saves the changes, resets the value of SomeText to empty string and returns to the view.
At this point I expect the text area to be empty because I have set ViewData["SomeText"] to string.Empty.
Why is text area value not updated to empty string after post action?
Here are the actions:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Message(int ID)
{
ViewData["ID"] = ID;
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Message(int ID, string SomeText)
{
// save Text to database
SaveToDB(ID, SomeText);
// set the value of SomeText to empty and return to view
ViewData["SomeText"] = string.Empty;
return View();
}
And the corresponding view:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<% using (Html.BeginForm())
{ %>
<%= Html.Hidden("ID", ViewData["ID"])%>
<label for="SomeText">SomeText:</label>
<%= Html.TextArea("SomeText", ViewData["SomeText"]) %>
<input type="submit" value="Save" />
<% } %>
</asp:Content>
The problem is that your ModelState is re-filled with the posted values.
What you can do is clear it on the Action that has the Post attribute :
ModelState.Clear();
The problem is the HtmlHelper is retrieving the ModelState value, which is filled with the posted data. Rather than hacking round this by resetting the ModelState, why not redirect back to the [get] action. The [post] action could also set a temporary status message like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Message(int ID, string SomeText)
{
// save Text to database
SaveToDB(ID, SomeText);
TempData["message"] = "Message sent";
return RedirectToAction("Message");
}
This seems to me like more correct behaviour.
The html helpers read the value from the ModelState. And there's no elegant way to override this behaviour.
But if you add this line after SaveToDB(ID, SomeText), it should work :
ModelState["SomeText"].Value =
new ValueProviderResult("", "", CultureInfo.CurrentCulture);
I tried everything, but only worked when I did something like this:
ModelState.Clear();
//This will clear the address that was submited
viewModel.Address = new Address();
viewModel.Message = "Dados salvos com sucesso!";
return View("Addresses", ReturnViewModel(viewModel));
Hope this helps.
Instead of using ModelState.Clear() which clears the whole modelstate, you can do ModelState.Remove("SomeText"), if you want to. Or render the Input without the htmlhelper-extensions.
They are designed to take the Value from ModelState instead of the Model (or viewdata).
That is a clientside behavior. I would recommend using javascript. If you use JQuery, you can do it like this:
<script type="text/javascript">
$(function(){ $("#SomeText").val("");});
</script>
I don't use Javascript anymore, but I believe in regular JS that it is like:
document.getElementById("SomeText").value = "";
(You would do this on one of the load events.
<body onload="...">
Hope this helps.
I am fairly certain the textarea is grabbing the value from the Request.Form under the hood since ViewData["SomeText"] is empty.
Is it possible that the model state has been updated with an error? I believe that it will pull the attempted value from the model state rather than from view data or the model if the model state isn't valid.
EDIT:
I'm including the relevant section of the source code from the TextArea HtmlHelper extension below. It appears to me that it does exactly what I expected -- if there has been a model error, it pulls the value from the model state, otherwise it uses it from ViewData. Note that in your Post method the "SomeText" key shouldn't even exist until you set it, i.e., it won't be carried forward from the version of the code that responds to the GET.
Since you explicitly supply a value to the ViewData, useViewData should be false, attemptedValue should be false unless an error has been set in the model state.
// If there are any errors for a named field, we add the css attribute.
ModelState modelState;
if (htmlHelper.ViewData.ModelState.TryGetValue(name, out modelState)) {
if (modelState.Errors.Count > 0) {
tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
}
}
// The first newline is always trimmed when a TextArea is rendered, so we add an extra one
// in case the value being rendered is something like "\r\nHello".
// The attempted value receives precedence over the explicitly supplied value parameter.
string attemptedValue = (string)htmlHelper.GetModelStateValue(name, typeof(string));
tagBuilder.SetInnerText(Environment.NewLine + (attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(name) : value)));
return tagBuilder.ToString(TagRenderMode.Normal);
Do s.th. like this:
add:
ModelState.Clear();
before the return statement of the submit buttons action method. Works for me. It could work for you.

Categories