Question

I'm trying to upload an image with a form, the problem is that most of examples are just to upload an image, but I want to add more data too, like name, url, etc.

This is the error I'm getting...

The input is not a valid Base64 string that contains a character that is not Base 64, more than two padding characters, or an invalid character among the padding characters.
[FormatException: La entrada no es una cadena Base 64 válida porque contiene un carácter que no es Base 64, más de dos caracteres de relleno o un carácter no válido entre los caracteres de relleno. ]
     System.Convert.FromBase64_Decode(Char* startInputPtr, Int32 inputLength, Byte* startDestPtr, Int32 destLength) +10739609
     System.Convert.FromBase64CharPtr(Char* inputPtr, Int32 inputLength) +130
     System.Convert.FromBase64String(String s) +41
     System.Web.Mvc.ByteArrayModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +265
     System.Web.Mvc.DefaultModelBinder.GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder) +59
     System.Web.Mvc.DefaultModelBinder.BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor) +653
     System.Web.Mvc.DefaultModelBinder.BindProperties(ControllerContext controllerContext, ModelBindingContext bindingContext) +180
     System.Web.Mvc.DefaultModelBinder.BindComplexElementalModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Object model) +106
     System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +2541
     System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +633
     System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) +494
     System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +199
     System.Web.Mvc.Async.<>c__DisplayClass1e.<BeginInvokeAction>b__16(AsyncCallback asyncCallback, Object asyncState) +1680
     System.Web.Mvc.Async.WrappedAsyncResult`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +59
     System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +151
     System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object state, BeginInvokeDelegate beginDelegate, EndInvokeDelegate`1 endDelegate, Object tag, Int32 timeout) +94
     System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeAction(ControllerContext controllerContext, String actionName, AsyncCallback callback, Object state) +525
     System.Web.Mvc.Controller.<BeginExecuteCore>b__1c(AsyncCallback asyncCallback, Object asyncState, ExecuteCoreState innerState) +82
     System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +73
     System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +151
     System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object callbackState, BeginInvokeDelegate`1 beginDelegate, EndInvokeVoidDelegate`1 endDelegate, TState invokeState, Object tag, Int32 timeout, SynchronizationContext callbackSyncContext) +105
     System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state) +595
     System.Web.Mvc.Controller.<BeginExecute>b__14(AsyncCallback asyncCallback, Object callbackState, Controller controller) +47
     System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +65
     System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +151
     System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object callbackState, BeginInvokeDelegate`1 beginDelegate, EndInvokeVoidDelegate`1 endDelegate, TState invokeState, Object tag, Int32 timeout, SynchronizationContext callbackSyncContext) +139
     System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +484
     System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +50
     System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__3(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState) +98
     System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +73
     System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +151
     System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object callbackState, BeginInvokeDelegate`1 beginDelegate, EndInvokeVoidDelegate`1 endDelegate, TState invokeState, Object tag, Int32 timeout, SynchronizationContext callbackSyncContext) +106
     System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +446
     System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +88
     System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +50
     System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +301
     System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

This is my code in the controller...

[HttpPost]
    public ActionResult Create(Feed feed)
    {
        if (ModelState.IsValid)
        {
           feed.UserModelID = UserRepo.GetUser(User.Identity.Name).UserModelID;
            if (Repo.InserFeed(feed) != -1)
            {
                ViewBag.success = "success";
            }
            else
            {
                ViewBag.success = "error";
            }
        }
        return View(feed);
    }

This is my model...

public class Feed
{
    public Int32 FeedID { get; set; }

    [Required(ErrorMessage = "The name is required")]
    [StringLength(32, MinimumLength = 8, ErrorMessage = "The name must be at least 8 characters")]
    public String Name { get; set; }

    [Required(ErrorMessage = "The url is required")]
    [Url(ErrorMessage = "Invalid URL")]
    public String Url { get; set; }

    [Required(ErrorMessage = "A type must be selected")]
    public Boolean IsAtom { get; set; }

    public Byte[] Image { get; set; }
    public String ImageIcon { get; set; }
    public Int32 UserModelID { get; set; }

    public virtual ICollection<Article> Articles { get; set; }
}

And this is my form...

using (Html.BeginForm("Create", "Feeds", FormMethod.Post, new { @class = "form-horizontal", role = "form", enctype = "multipart/form-data" }))
            {
                Html.AntiForgeryToken();
                Html.ValidationSummary(true);
                <fieldset>
                    <legend>Feed basic data</legend>
                    <div class="input-group">
                        <span class="input-group-addon glyphicon glyphicon-font"></span>
                        @Html.TextBoxFor(m => m.Name, new { @class = "form-control", placeholder = "Site name" })
                        @Html.ValidationMessageFor(m => m.Name)
                    </div>
                    <div class="input-group">
                        <span class="input-group-addon glyphicon glyphicon-link"></span>
                        @Html.TextBoxFor(m => m.Url, new { @class = "form-control", placeholder = "Feed URL" })
                        @Html.ValidationMessageFor(m => m.Url)
                    </div>
                    <div class="input-group">
                        <span class="input-group-addon glyphicon glyphicon-picture"></span>
                        @Html.TextBoxFor(m => m.Image, new { @class = "form-control", type = "file" })
                        @Html.ValidationMessageFor(m => m.Image)
                    </div>
                </fieldset>
                <fieldset>
                    <legend>Feed type</legend>
                    <label class="radio-inline">
                        @Html.RadioButtonFor(m => m.IsAtom, false, new { @checked = "checked", id = "rss" })
                        Rss
                    </label>
                    <label class="radio-inline">
                        @Html.RadioButtonFor(m => m.IsAtom, true, new { id = "atom" })
                        Atom
                    </label>
                    @Html.ValidationMessageFor(m => m.IsAtom)
                </fieldset>
                <br />
                <div class="input-group">
                    <button type="submit" class="btn btn-primary btn-sm">Add feed</button>
                </div>
                <br />
                if (ViewBag.Success != null)
                {
                    if (ViewBag.Success == "success")
                    {
                        <div class="alert alert-success"><strong>Great!</strong> you added a new feed.</div>
                    }
                    else
                    {
                        <div class="alert alert-danger"><strong>Sorry!</strong> but that is not a valid url.</div>
                    }
                }
            }

I think the problem comes when the image data that comes from the form is being bind to the Feed image property. It would be nice if you have some examples to show.

Was it helpful?

Solution

Here goes my solution, say you have following ViewModel -

public class FileViewModel
{
    public string Name { get; set; }
    public string Description { get; set; }
    public HttpPostedFileBase ThumbnailFile { get; set; }
}

Then you have a controller action to render a form -

    public ActionResult Index()
    {
        FileViewModel model = new FileViewModel();
        return View(model);
    }

And in the View, you display all fields as shown below -

@model MVC.Controllers.FileViewModel

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

@using (Html.BeginForm("Submit", "Person", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    @Html.LabelFor(model => model.Name)
    @Html.EditorFor(model => model.Name)
    @Html.ValidationMessageFor(model => model.Name)

    @Html.LabelFor(model => model.Description)
    @Html.EditorFor(model => model.Description)
    @Html.ValidationMessageFor(model => model.Description)

    <input type="file" name="ThumbnailFile" id="ThumbnailFile" />
    <input type="submit" value="Save" />
}

And when you click Submit button, you get hit to following controller action -

    public ActionResult Submit(FileViewModel model)
    {
        return View();
    }

Ans when you debug, you get all the values as shown below -

enter image description here

OTHER TIPS

the image will be in the form of HttpPostedFileBase not byte[], and will contain stuff like filename, length and content type, you can convert into a byte[] on the server before you store it

you could add this to your model.

[NotMapped]
public HttpPostedFileBase ImageToUpload {get; set;}

and TextBoxFor in the View to this property

then on the sever:

var contentType = ImageToUpload.ContentType;
var ImageData = new byte[ImageToUpload.ContentLength];
ImageToUpload.InputStream.Read(ImageData, 0, ImageToUpload.ContentLength);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top