0

I am trying to post a form data that includes an image from Angularjs client to a Web API backend, but gets an error: "Could not create an instance of type System.Web.HttpPostedFileBase. Type is an interface or abstract class and cannot be instantiated. Path 'ProfileImage', line 1, position 299."

My angular code is

        $scope.RegisterUser = function () {
          $http({
              method: 'POST',
              url: 'http://localhost:2434/api/Account/BrandRegistration/',
              data: $scope.brandForm,
              file : $scope.brandForm.ProfileImage
          }).then(function successCallback(response) {
              // this callback will be called asynchronously
              // when the response is available
              console.log("libin");
          }, function errorCallback(response) {
              // called asynchronously if an error occurs
              // or server returns response with an error status.
          });

My web api method is

     public async Task<IHttpActionResult> PostBrandRegistration(BrandRegistration brandVM)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
       var  roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new ApplicationDbContext()));
        if (!roleManager.RoleExists("brand"))
        {
            var role = new Microsoft.AspNet.Identity.EntityFramework.IdentityRole();
            role.Name = "brand";
            roleManager.Create(role);
        }
        if (!roleManager.RoleExists("influencer"))
        {
            var role = new Microsoft.AspNet.Identity.EntityFramework.IdentityRole();
            role.Name = "influencer";
            roleManager.Create(role);
        }
        var user = new ApplicationUser()
        {
            UserName = brandVM.Email,
            Email = brandVM.Email
        };
        var fileName = "";
        var file = HttpContext.Current.Request.Files.Count > 0 ?
       HttpContext.Current.Request.Files[0] : null;
        if (file != null && file.ContentLength > 0)
        {
             fileName = Path.GetFileName(file.FileName);

            var path = Path.Combine(
                HttpContext.Current.Server.MapPath("~/App_Data/ProfileImage"),
                fileName
            );

            file.SaveAs(path);
        }
        user.BrandUser = new BrandUser()
        {
            FullName = brandVM.FullName,
            ContentType = brandVM.ContentType,
            Description = brandVM.Description,
            URL = brandVM.URL,
            ContactPerson = brandVM.ContactPerson,
            Position = brandVM.Position,
            PhoneNumber = brandVM.PhoneNumber,
            ContactEmail = brandVM.Email,
            Address = brandVM.Address,
            MarketPlace = brandVM.MarketPlace,
            Campaigns = brandVM.Campaigns,
            InfluencerRating = brandVM.InfluencerRating,
            ProfileImage = fileName
        };
        user.BankDetail = new BankDetail()
        {
            AccountNumber = brandVM.AccountNumber,
            AccountName = brandVM.AccountNumber,
            IRD = brandVM.IRD,
            GST = brandVM.GST
        };
        IdentityResult result = await UserManager.CreateAsync(user, brandVM.Password);
        if (!result.Succeeded)
        {
            return GetErrorResult(result);
        }
        else
        {
            await this.UserManager.AddToRoleAsync(user.Id, "brand");

            return Ok();
        }
     }

And my View Model is

public class BrandRegistration
{    
    public string Email { get; set; }
    public string Password { get; set; }
    public string PasswordConfirmation { get; set; }

    public string FullName { get; set; }
    public string ContentType { get; set; }
    public HttpPostedFileBase ProfileImage { get; set; }       
    public string Description { get; set; }
    public string URL { get; set; }
    public string ContactPerson { get; set; }
    public string Position { get; set; }
    public string Company { get; set; }
    public int PhoneNumber { get; set; }
    public string ContactEmail { get; set; }
    public string Address { get; set; }
    public string AccountNumber { get; set; }
    public string AccountName { get; set; }
    public string IRD { get; set; }
    public string GST { get; set; }
    public bool MarketPlace { get; set; }
    public bool Terms { get; set; }
    public double InfluencerRating { get; set; }
    public int Campaigns { get; set; }
}

I really appreciate if someone can advice me of where i have gone wrong.

  • Most of the times, the image is sent first mostly using a multipart/form-data, then if the return of that call is OK, you send a request to send the other data. The image is in a temp folder, when you save the data, you can move the image to its "final" destination. – jpgrassi Jan 14 '16 at 13:33
  • @jpgrassi : Prefer it send as one request. Can we not do that way? – LibinJoseph Jan 14 '16 at 13:39
  • I posted an answer here: http://stackoverflow.com/questions/34101258/unable-to-configure-web-api-for-content-type-multipart/34154477#34154477 that has an example on how to post an image alongside with metadata. I think it can help you. – jpgrassi Jan 14 '16 at 13:49
  • @jpgrassi : I guess I am one step closer now. provider.FormData.GetValues("string") has only one property in it called data, which is the object that was send from client side. But how do i access the fields in thats object – LibinJoseph Jan 14 '16 at 14:38
  • I guess you'll have to search on how to send other fields (metadata) in a multipart-/formdata in angular. – jpgrassi Jan 14 '16 at 15:41
  • See an example of what I commented above: http://stackoverflow.com/questions/28023703/multipart-form-upload-image-and-json – jpgrassi Jan 14 '16 at 15:47
  • Still have not managed to get the C# side working. @jpgrassi : There is no C# code in it. – LibinJoseph Jan 14 '16 at 23:40
  • 1
    Thank you @jpgrassi . I have got it working now – LibinJoseph Jan 15 '16 at 03:49

1 Answers1

0

I'm not familiar with .NET, but you definitely should use form data on the client side.

var fd = new FormData();
            fd.append('file', $scope.brandForm.ProfileImage);
            fd.append('data', $scope.brandForm)
$http({
              method: 'POST',
              url: 'http://localhost:2434/api/Account/BrandRegistration/',
              data: fd
              transformRequest: angular.identity,
              headers: {'Content-Type': undefined}
          })
Oleksii
  • 328
  • 3
  • 17
  • Ok, need some more clarity on this. What is angular.identity and how do we add Formdata to the http request – LibinJoseph Jan 14 '16 at 13:38
  • @LibinJoseph I've updated my answer, added `data: fd`. I recomend to read [this](https://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs) article, maybe it could help – Oleksii Jan 14 '16 at 13:53
  • I have corrected by Angularcode to match this. checking the C# part now and will update – LibinJoseph Jan 14 '16 at 14:36