ASP.NET MVC2 +file uploading (HttpPostedFileBase class) - asp.net-mvc-2

I have problem with uploading my file. I want to upload it from my edit view:
<%
using (Html.BeginForm("edit","profile",FormMethod.Post, new { enctype="multipart/form-data" }))
{%>
<%: Html.ValidationSummary(true) %>
<%: ViewData["ErrorMessage"] %>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
<%: Html.LabelFor(model => model.Image) %>
</div>
<div class="editor-field">
<input type="file" id="Image" name="Image" />
<label id="LabelErrorImage" class="errorMessage" />
</div>
<p>
<input type="submit" value="Save" onclick="return Validate(); return false;"/>
</p>
</fieldset>
<% } %>
I want to use HttpPostedFileBase class. My edit action:
[Authorize]
[HttpPost]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(string id, HttpPostedFileBase file, FormCollection formValues)
{
if (ModelState.IsValid)
{
if (file != null && file.ContentLength > 0)
{
CustomHelpers.createFolder();
var tmpPath = MyConfig.UPLOAD_FILE_PATH + "/" + Membership.GetUser().ProviderUserKey.ToString();
var path = Path.Combine(Server.MapPath(MyConfig.UPLOAD_FILE_PATH), "Avatar");
var fileExtension = Path.GetExtension(file.FileName);
file.SaveAs(path);
user.Image = "Avatar";
}
adventureDB.SaveChanges();
return RedirectToAction("Index");
}
}
But I always have empty the file object, why????? Do you have any ideas, suggestions why it can work like that? Maybe there is problem how I pass on the file value to my Edit action?
EDIT:
IT IS REALLY STRANGE AS EVEN WHEN I REMOVE
using (Html.BeginForm("Index","Profile",FormMethod.Get, new { enctype="multipart/form-data" }))
The page source still has:
<body>
<form method="post" action="6111e591-b92d-4bcb-b214-ab8f664b35f9" id="form1">
I mean I can not change the tag but have no idea why :/

Try changing:-
public ActionResult Edit(string id, HttpPostedFileBase file,
FormCollection formValues)
to:-
public ActionResult Edit(string id, HttpPostedFileBase image,
FormCollection formValues)
as the name of your input is image
<input type="file" id="Image" name="Image" />
edit
To be honest something else is stopping the binding of image. Is this the whole form that you have posted?
A few things to test
You have HTTPOST decorating your method twice, although I don't believe this should make a difference.
View the source and make sure there is nothing else named name=image in the source.
Make sure you empty your cache and make sure source is correct before testing again
Try using <form action="/profile/index" method="post" enctype="multipart/form-data">
Judging by your last edit you have a problem with master pages/layout? Is this a mvc/webforms hybrid?

The solution of this problem when:
We use Master.Site,
We want to upload file in a view,
We are sure that it should work but we all the time has null,
Then:
Guys were right - I had wrong name in my view - check it!
Check source code of your view and if you have 2 < form > tags you should remove the < form > tag from Master site as then the second one is ignored!
Now it should work.

Well, in your view you named the file input 'image' but your action method accepts a parameter called 'file'. Rename one of those and it should work.

Related

Posting Html with images (WYSIWYG) to ASP.net core controller

I'm having trouble posting my wysiwyg content to my controller in asp.net core. I can't seem to get any value from the form editor. The value for the Content property comes to the controller as null. I'm using the summernote form editor to handle my richtext box editor.
Here is my code
public class Editor
{
public int EditorId { get; set; }
public string Content { get; set; }
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Editor editor)
{
if (ModelState.IsValid)
{
_context.Add(editor);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(editor);
}
View:
<h2>Create</h2>
<h4>Editor</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Content" class="control-label"></label>
<textarea asp-for="Content" id="summernote" name="editordata"></textarea>
<span asp-validation-for="Content" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
<script>
$(document).ready(function () {
$('#summernote').summernote();
});
</script>
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.9/summernote.js"></script>
}
#section Styles{
<!-- include libraries(jQuery, bootstrap) -->
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.css" rel="stylesheet">
<!-- include summernote css/js -->
<link href="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.9/summernote.css" rel="stylesheet">
}
So the issue is when I post the form it's gets to the controller but the content comes over as null. I'm not sure how to post the content
Here are my thoughts, I'm thinking i'm missing a some attribute that allows html to come over the wire to my controller, but all the reserach i've found is that asp.net core doesn't require that. Or I need to handle this type of request in the middleware pipeline, but that doesn't make much sense since it's just html strings i'm sending over the wire to the controller.
It looks like the top of your view was not left out, I assume you have Editor as model.
The problem is on your text area you are using both asp-for and then setting the id and name to something that doesn't match your model property.
You should just use asp-for and let it decide the id and name instead of adding those yourself.
What is really getting posted is a string named editordata because you used that name on the textarea. remove that and it will be named Content to match the property of the model
You also don't need the [Bind] attribute shown in the controller action in your screenshot.
I have been sitting with the same issue and was able to resolve it due to Joe's answer!
Could I suggest working on the summernote class for the text area instead of using your id?
I noticed when I use the id that my textarea's display property doesn't get set to none, but it works when i use the class="summernote".
<textarea asp-for="Instructions" class="summernote"></textarea>
<script>
$(document).ready(function () {
$('.summernote').summernote();
});
</script>
Put this script in your page head:
<script src="https://cdn.ckeditor.com/4.13.0/standard/ckeditor.js"></script>
Lets say you have model called ForumModel where you save contents of editor. Property where you your content is saved is called answer:
public string Answer { get; set; }
So in your view you have following tag:
#model ForumModel
Therefore if you want to add editor:
<textarea id="editor1" asp-for="#Model.Answer" class="form-control" required=""></textarea>
<script>
CKEDITOR.replace("editor1");
</script>
And now all that is left is to call your controller on submit button. When your form is submitted you go to constructor that saves your contents.
public IActionResult Reply(ForumModel forumModel)
{
forumModel.SaveReply();
return RedirectToAction("SomeRandomPage");
}

ASP.NET Html Extension not firing?

I have a couple of Extension classes, borrowed from various places, and they both work - individually. When I try to use both on the same page it appears one does not work. Here is the setup:
MVC 2 (no path for upgrading it to MVC 3 or 4)
HtmlPrefixScopeExtensions - http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
FileBoxHtmlHelperExtension -
http://forums.asp.net/p/1566760/4033836.aspx
The .ascx page code looks like:
<%# Control Language="C#" AutoEventWireup="true" Inherits="System.Web.Mvc.ViewUserControl<PB.WMATA.ApplicationServices.ViewModels.Files.CIPDocumentAndFile>" %>
<%# Import Namespace="Company.Web.Extensions"%>
<div class="editorRow">
<% using(Html.BeginCollectionItem("docs")) { %>
<%= Html.Hidden("CIPDocument.Id", (Model != null) ? Model.Id : 0) %>
<label for="CIPNumber">Document Name:</label>
<%= Html.TextBox("CIPNumber", (Model != null) ? Model.CIPNumber : "", new { #size = "50", #maxlength = "255" })%>
<%= Html.ValidationMessage("CIPNumber")%>
<% if (Model != null && Model.FileName != null && Model.FileName.Length > 0) { %>
<label>Current File:</label>
<%= Model.FileName %>
<% } else { %>
<label>
File Upload:
<%= Html.FileBoxFor(m => m.HttpPostedFileBase) %>
</label>
<% } %>
delete
<% } %>
</div>
The output for this looks like:
<div class="editorRow">
<input name="docs.index" autocomplete="off" value="1809201d-2143-4da3-ba34-e443a332c516" type="hidden">
<input id="docs_1809201d-2143-4da3-ba34-e443a332c516__CIPDocument_Id" name="docs[1809201d-2143-4da3-ba34-e443a332c516].CIPDocument.Id" value="0" type="hidden">
<label for="CIPNumber">
Document Name:
</label>
<input id="docs_1809201d-2143-4da3-ba34-e443a332c516__CIPNumber" maxlength="255" name="docs[1809201d-2143-4da3-ba34-e443a332c516].CIPNumber" size="50" value="" type="text">
<label>
File Upload:
<input id="HttpPostedFileBase" name="HttpPostedFileBase" type="file">
</label>
<a href="#" class="deleteRow">
delete
</a>
</div>
Notice the FileUpload control did not get the HtmlPrefixScope. I expected it to be:
<input id="docs_1809201d-2143-4da3-ba34-e443a332c516__HttpPostedFileBase" name="docs[1809201d-2143-4da3-ba34-e443a332c516].HttpPostedFileBase" type="file">
I am not quite savvy enough with extensions to see what may be going on. I suspect that the collection extension is being handled before it tries to handle the filebox extension. Any ideas?
After digging in it turns out that I needed to get at the TemplateInfo.HtmlFieldPrefix value as the Html.BeginCollectionItem("docs") call had altered it. Was really simple once I understood the lifecycle of the TemplateInfo object. Here is the altered code for the FileBox & FileBoxFor code pieces:
public static MvcHtmlString FileBox(this HtmlHelper htmlHelper, string name, IDictionary<String, Object> htmlAttributes)
{
// If the HtmlFieldPrefix has been altered (see HtmlPrefixScopeExtensions class!!) then this will work with it...
var htmlFieldPrefix = htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix;
name = (!string.IsNullOrEmpty(htmlFieldPrefix) ? string.Format("{0}.", htmlFieldPrefix) : "") + name;
var tagBuilder = new TagBuilder("input");
tagBuilder.MergeAttributes(htmlAttributes);
tagBuilder.MergeAttribute("type", "file", true);
tagBuilder.MergeAttribute("name", name, true);
tagBuilder.GenerateId(name);
ModelState modelState;
if (htmlHelper.ViewData.ModelState.TryGetValue(name, out modelState))
{
if (modelState.Errors.Count > 0)
{
tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
}
}
return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.SelfClosing));
}

How can I call a controller action passing a fixed string and a value from a dropdown combo?

I'm sure what I want to do is possible, but I can't figure out how.
I have a view which shows some information about the selected user, including their roles. I have added a dropdown to the view showing all the roles and want to have a button which will add the selected role from the dropdown to the current user. To allow this I have a controller with this method:
public ActionResult AddUserRole (string userName,string roleName)
{
if (Roles.IsUserInRole (userName,roleName)==false)
{
Roles.AddUserToRole (userName,roleName);
}
return RedirectToAction("Profile", "Profile",new {userName=userName});
}
but I can't figure out how I set the selected item in the dropdown from the view to be the string roleName parameter in the controller method. I can set the userName easily enough as this is static. What am I missing? Here's my view, or at least the relevant bit:
<%
using (Html.BeginForm( "AddUserRole", "Account",new {userName=Model.UserName}))
{%>
<div id="AddRoleToUser">
<asp:Label ID="Label1" runat="server" Text="Select new role."></asp:Label>
<%:Html.DropDownListFor(model=>model.Roles,new SelectList (Model.Roles),null,new {id="roleName"}) %>
<input type="submit" value="Create" />
</div>
<% }%>
<%}%>
Model.Roles is an IEnumerable<String> type;
it seems that changing the name of the parameter in the controller action gave me what I wanted:
public ActionResult AddUserRole (string userName,string roles)
{
if (Roles.IsUserInRole (userName,roles)==false)
{
Roles.AddUserToRole (userName,roles);
}
return RedirectToAction("Profile", "Profile",new {userName=userName});
}
<%
using (Html.BeginForm( "AddUserRole", "Account",new {userName=Model.UserName}))
{%>
<div id="AddRoleToUser">
<asp:Label ID="Label1" runat="server" Text="Select new role."></asp:Label>
<%:Html.DropDownListFor(model=>model.Roles,new SelectList (Model.Roles)) %>
<input type="submit" value="Create" />
</div>
<% }%>
<%}%>
not sure how I would alias that to something else, but for now it works so it'll be ok.

What should I use to pass value in asp.net mvc posting form?

I am passing the edited value and retrieving it back but I dont get back the id value.. how do I get back the value for Id...The id value will actually remain the same..all I need to do is pass it back again...
public ActionResult EditValue(int id)
{
ViewData["id"]=id;
ViewData["Value"]=GetOriginalValue();
return View();
}
[HttpPost]
public ActionResult EditValue(string Value)
{
//How do I get the id value back..it will always be the same
UpdateValue(id,Value);
}
//---VIEW--
<% Html.BeginForm(); %>
<div class="editor-label">
<%= Html.Label("Value")%>
</div>
<div class="editor-field">
<%= Html.TextBox("Value",ViewData["Value"])%>
<%= Html.ValidationMessage("Value")%>
</div>
<p>
<input type="submit" value="Update" />
</p>
<% Html.Hidden("id", ViewData["id"]);%>
<% Html.EndForm(); %>
if you put int id into your parameters for the post, it should pick up the hidden form element... Or you can use the FormCollection class and access the individual form elements.
So your method signature would look like:
public ActionResult EditValue(int id, string Value)
or
public ActionResult EditValue(FormCollection form)

Passing Parameters from textboxes in a view to a controller in ASP.Net MVC2

I am trying out ASP.Net MVC2 by building a small sample website which, amongst other features provides the user with a 'Contact Us' page. The idea is to allow a user to enter their name, email address, message subject and message. To send the message the user clicks on an ActionLink. This is the view:
<% Html.BeginForm(); %>
<div>
<%: Html.Label("Name")%>
<br />
<%: Html.TextBox("txtName", "",new { style = "width:100%" })%>
<br />
<%: Html.Label("Email address")%>
<br />
<%: Html.TextBox("txtEmail", "", new { style = "width:100%" })%>
<br />
<%: Html.Label("Subject")%>
<br />
<%: Html.TextBox("txtSubject", "", new { style = "width:100%" })%>
<br />
<%: Html.Label("Message")%>
<br />
<%: Html.TextBox("txtMessage", "", new { style = "width:100%" })%>
</div>
<div style='text-align: right;'>
<%:
Html.ActionLink("Send", "SentEmail", new { name = Html.g, sender = "txtEmail", subject = "txtSubject", message="txtMessage" })
%>
</div>
<% Html.EndForm(); %>
The idea is once the ActionLink has been clicked a method in the controller is called into which the username, email address, subject and message will be passed. This is the method in the controller:
public ActionResult SentEmail(string name, string sender, string subject, string message)
{
//Send email here and then display message contents to user.
ViewData["Name"] = name;
ViewData["Message"] = message;
ViewData["ThankyouMessage"] = "Thank you for contacting us. We will be in touch as soon as possible.";
return View();
}
However... when I click the link the values which are passed into the method are null. I have tried creating a route to do this but it doesn't work either. Should I be using another method?
Thank you,
Morris
Actually to achieve what you want to is easier than in your sample. Never heard about Model classes, Model Binder and strong typed views? Here thery are
Model class
public class ContactUsModel
{
public string Name { get; set; }
public string Email { get; set; }
public string Subject { get; set; }
public string Message { get; set; }
}
Then in your controller you should have two action: the first that show the form with default values and the second that receive the form with the data placed by the user. These two actions maps exactly to the HttpGet and HttPost verbs.
[HttpGet]
public virtual ActionResult ContactUs() {
ContactUsModel model = new ContactUsModel();
return View(model);
}
[HttpPost]
public virtual ActionResult ContactUs( ContactUsModel model ) {
//e.g. Save the contact request to database
}
To use this your view shal be strong typed to the ContactUsModel class
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ContactUsModel>" %>
<% using (Html.BeginForm()) { %>
<div>
<%: Html.LabelFor(model => model.Name) %><br />
<%: Html.TextBoxFor(model => model.Name, new { style = "width:100%" })%>
</div>
<div>
<%: Html.LabelFor(model => model.Email) %><br />
<%: Html.TextBoxFor(model => model.EMail, new { style = "width:100%" })%>
</div>
<div>
<%: Html.LabelFor(model => model.Subject) %><br />
<%: Html.TextBoxFor(model => model.Subject, new { style = "width:100%" })%>
</div>
<div>
<%: Html.LabelFor(model => model.Message) %><br />
<%: Html.TextAreaFor(model => model.Message, new { style = "width:100%" })%>
</div>
<div>
<input type="submit" value="Save" />
</div>
<% } %>
the magic of everything this is called ModelBinder. Please read more and more about MVC here.
The action link isn't going to trigger a http post nor will it pass in the values of your form fields, just a http get and not passing through any form data - ideally you'd use an input submit button to post the data. What is certain is that it is good practise that any request that causes creating/updating of data should be done via a http post.
Submit button would just be like.
<input type="submit" value="Send" />
You then have several ways of accessing the form data firstly you could use a FormCollection to access the data
[HttpPost]
public ActionResult SendEmail(FormCollection collection)
{
string email = collection["txtEmail"];
...
}
Secondly you could use the method parameters and rely on model binding, but you must make sure field names match the parameter name so
<%: Html.TextBox("txtEmail", "", new { style = "width:100%" })%>
...would require...
[HttpPost]
public ActionResult SendEmail(string txtEmail)
{
...
}
If this form isn't being posted to the same action thats return the view then you'd also need to change your begin form tag, ideal you should use 'using' with it as well. So you'd get:
<% using (Html.BeginForm("SendEmail", "<controller-name>"))
{ %>
.... form fields in here ...
<input type="submit" value="Send" />
<% } %>
If the button isn't suitable for your design you could use something like:
<input type="image" src="<%: Url.Content("~/Content/images/myimage.gif") %>" value="Send" />
This would have the same effect. To trigger a post from an a tag though you'd need to look at using javascript, I can't remember the exact syntax but off hand I think if you used jquery you'd be looking at something like: (form a single form page only)
Send
But then you create a dependency on javascript where as really you should try have your site degrade gracefully so it can be used by visitors with javascript disabled. There are perhaps more advanced way of achieving this whilst meeting design requirements but that can get heavily into client side code which is probably outside of what you want for your sample.