Angularjs : Post form data with an image to Web API backend - c#

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.

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}
})

Related

Getting Http Error Code 411 : Length Required

When I am trying to upload a file using following code I am receiving Length Required error. Please note that if I am uploading a TEXT file then I don't see any issues. But when I upload WORD or PDF I am seeing the error. FYI, I am able to see to Content-Length in my request header in both occasions. Any help would be much appreciated.
internal static class CreateFile
{
private static string _Server = "MyServer.com";
private static string _Database = "ACTIVE";
internal static async Task<string> CreateFileInFolder(string _AuthToken, string _FolderId, string _FileLocation)
{
// Force TLS 1.2 instead of the default value.
ServicePointManager.ServerCertificateValidationCallback = (s, cert, chain, ssl) => true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//folder creation URI
string _FileCreateUri = $"https://{_Server}/api/v2/customers/1/libraries/{_Database}/folders/{_FolderId}/documents";
FileInfo _FileDetails = new (_FileLocation);
string _Result = "";
FileRoot _FileRoot = new()
{
doc_profile = new FileProfile()
{
author = "ADMIN",
comment = "New Import",
default_security = "private",
name = _FileDetails.Name,
custom1 = "Test",
custom2 = "Test",
custom17 = "12345",
access = "full_access",
database = _Database,
size = _FileDetails.Length,
#class = "DOC",
type = "ACROBAT",
type_description = "",
wstype = "document"
},
audit = new FileAudit()
{
comments = "Test Import"
},
keep_locked = false,
warnings_for_required_and_disabled_fields = true
};
byte[] _FileBytes = File.ReadAllBytes(_FileDetails.FullName);
string _Boundary = $"----------{DateTime.Now.Ticks:x}";
MultipartFormDataContent _MultipartFormDataContent = new(_Boundary)
{
{
JsonContent.Create(_FileRoot), "profile"
},
{
new StreamContent(new MemoryStream(_FileBytes), _FileBytes.Length), "file"
}
};
_MultipartFormDataContent.Headers.Remove("Content-Type");
_MultipartFormDataContent.Headers.TryAddWithoutValidation("Content-Type", $"multipart/form-data; boundary={_Boundary}");
using (HttpClient _HttpClient = new())
{
//include authentication token in request header
_HttpClient.DefaultRequestHeaders.Add("X-Auth-Token", _AuthToken);
using (HttpResponseMessage _HttpResMsg = await _HttpClient.PostAsync(_FileCreateUri, _MultipartFormDataContent))
{
if (_HttpResMsg.StatusCode == HttpStatusCode.Created)
{
_Result = _HttpResMsg.Content.ReadAsStringAsync().Result;
}
}
}
//MessageBox.Show($"Json profile newly created folder: {_HttpResMsg.Content.ReadAsStringAsync().Result}", "New Folder Profile", MessageBoxButton.OK);
return _Result;
}
public class FileAudit
{
public string comments { get; set; }
}
public class FileProfile
{
public string author { get; set; }
public string access { get; set; }
public string comment { get; set; }
public string #class { get; set; }
public string database { get; set; }
public string default_security { get; set; }
public string name { get; set; }
public long size { get; set; }
public string type { get; set; }
public string type_description { get; set; }
public string wstype { get; set; }
public string custom1 { get; set; }
public string custom2 { get; set; }
public string custom17 { get; set; }
}
public class FileRoot
{
public FileProfile doc_profile { get; set; }
public FileAudit audit { get; set; }
public bool keep_locked { get; set; }
public bool warnings_for_required_and_disabled_fields { get; set; }
}
}
Tried to use HttpRequestMessage by setting Content-Length but again able to upload TEXT files but not WORD or PDF files.

System.InvalidOperationException ASP.NET C#

Solved Solved Solved
Error;
System.InvalidOperationException: 'An exception was thrown while attempting to evaluate a LINQ query parameter expression. See the inner exception for more information. To show additional information call 'DbContextOptionsBuilder.EnableSensitiveDataLogging'.'
When Is It Happening;
When I try to use register method with those properties, Its poping up on return claims.ToList();:
public string Email { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string? MiddleName { get; set; }
public string LastName { get; set; }
My Controller Method
[HttpPost("register")]
public IActionResult Register(RegisterDTO registerDTO)
{
var result = _authService.Register(registerDTO, registerDTO.Password);
if (!result.Success) return BadRequest(result);
var createAccessTokenResult = _authService.CreateAccessToken(result.Data);
if (!result.Success) return BadRequest(result);
var createdAccessTokenDataWithSuccessResult = new SuccessDataResult<AccessToken>(createAccessTokenResult.Data, result.Message);
return Ok(createdAccessTokenDataWithSuccessResult);
}
DataAccess Layer
public List<OperationClaim> GetClaims(User user)
{
var claims = from uoc in Context.UserOperationClaims
join oc in Context.OperationClaims
on uoc.OperationClaimId equals oc.Id
where uoc.UserId == user.Id
select new OperationClaim
{ Id = oc.Id, Name = oc.Name };
return claims.ToList();
}
Entity User;
public int Id { get; set; }
public string FirstName { get; set; }
public string? MiddleName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public byte[] PasswordSalt { get; set; }
public byte[] PasswordHash { get; set; }
public bool Status { get; set; }
I solved it
The problem is, Im was not sending parameter user when It is success on Business Layer
public IDataResult<User> Register(RegisterDTO registerDTO, string password)
{
BusinessRules.Run(CheckTheEmailIsAlreadyRegistered(registerDTO));
byte[] passwordHash, passwordSalt;
HashingHelper.CreatePasswordPash(password, out passwordHash, out passwordSalt);
var user = new User()
{
Email = registerDTO.Email,
FirstName = registerDTO.FirstName,
MiddleName = registerDTO.MiddleName,
LastName = registerDTO.LastName,
PasswordHash = passwordHash,
PasswordSalt = passwordSalt,
Status = true
};
var result = _userService.Add(user);
if (!result.Success) return new ErrorDataResult<User>();
return new SuccessDataResult<User>(**user**);
}

ASP.NET Core Web API - How to upload multiple files to specific directory

In ASP.NET Core Web API, I have two models:
public class Employee
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmployeeCode { get; set; }
public virtual ICollection<EmployeeAttachment> EmployeeAttachments { get; set; }
}
public class EmployeeAttachment
{
public Guid Id { get; set; }
[ForeignKey("EmployeeId")]
public Guid? EmployeeId { get; set; }
public string FileType { get; set; }
public string FileName { get; set; }
public string FilePath { get; set; }
public virtual Employee Employee { get; set; }
}
An employee will have several attached files. The file will be stored in this directory in the Web API.
Resources -> Attachments
Then I have this DTO.
DTO:
public class EmployeeDetailRequestDto
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmployeeCode { get; set; }
public Guid? EmployeeId { get; set; }
public string FileType { get; set; }
public string FileName { get; set; }
public string FilePath { get; set; }
}
BaseResponse:
public class BaseResponse
{
public string ResponseCode { get; set; }
public string ResponseDescription { get; set; }
}
Mapping:
CreateMap<EmployeeDetailRequestDto, Employee>().ReverseMap();
Then eventually put everything into the service.
Service.
Interface:
public interface ICreateEmployeeAsync
{
Task<BaseResponse> CreateEmployeeAsync(EmployeeDetailRequestDto model);
}
public async Task<BaseResponse> CreateEmployeeAsync(EmployeeDetailRequestDto model) : ICreateEmployeeAsync
{
var response = new BaseResponse();
using (var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
var employee = _mapper.Map<Employees>(model);
employee.FirstName = model.FirstName,
employee.LastName = model.LastName,
employee.EmployeeCoder = model.EmployeeCode
// Insert Employee Data into the DB
_context.Employees.Add(employee);
await _context.SaveChangesAsync();
var folderName = Path.Combine("Resources", "Attachments");
var pathToSave = Path.Combine(Directory.GetCurrentDirectory(), folderName);
foreach (var singleAttachemnt in model)
{
EmployeeAttachment res = new EmployeeAttachment();
res.EmployeeId = employee.Id;
res.FileType = singleAttachemnt.FileType;
res.FileName = singleAttachemnt.FileName;
res.FileName = singleAttachemnt.FilePath;
// Insert Attachment Data into the DB
_context.EmployeeAttachments.Add(res);
await _context.SaveChangesAsync();
}
response.StatusCode = (int)HttpStatusCode.Created;
response.Successful = true;
response.Data = _mapper.Map<BaseResponse>(employee);
response.Message = "Employee created successfully!";
transaction.Complete();
return response;
};
}
Controller:
[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<BaseResponse>> CreateEmployeeAsync([FromBody] EmployeeDetailRequestDto model)
{
var result = await _employeeProfileService.CreateEmployeeAsync(model);
return StatusCode(result.StatusCode, result);
}
I got this error:
Error CS1579 foreach statement cannot operate on variables of type 'EmployeeDetailRequestDto' because 'EmployeeDetailRequestDto' does not contain a public instance or extension definition for 'GetEnumerator'
and model is highlighted in var singleAttachemnt in model
How do I resolve this error, and also save the attachments into the specified folder.
Then, FileName, FileType and FilePath into the DB?
Thanks
In your code, model is of type EmployeeDetailRequestDto which does not have any collections in it. EmployeeDetailRequestDto represents a single attachment for an Employee. It's only in your database entity Employee that you have an Attachments collection.
What you likely want to do is add an EmployeeAttachmentRequestDto collection to your EmployeeDetailRequestDto, and then loop on that.

Trying to upload a file to database with asp.net core

i am struggling to load a file into a database with ASP.NET Core. What could i be doing wrong.
This is what i have in my Model
namespace BeeshoekCWPortal.Models
{
public class CWRecords
{
public int Id { get; set; }
public string RecordName { get; set; }
public byte[] Document { get; set; }
[DisplayFormat(DataFormatString ="{0:d}")]
public DateTime DateAdded { get; set; }
public int CWId { get; set; }
[ForeignKey("CWId")]
public virtual ContingentWorker CW { get; set; }
}
}
This is what I have in My ViewModel
namespace BeeshoekCWPortal.ViewModel
{
public class CWandRecordsViewModel
{
public int CWId { get; set; }
public string Title { get; set; }
public string FullNames { get; set; }
public string Surname { get; set; }
public string DateofBirth { get; set; }
public string IdPassportNumber { get; set; }
public string Gender { get; set; }
public string Race { get; set; }
public string Nationality { get; set; }
public IFormFile Document { get; set; }
public CWRecords NewRecordObj { get; set; }
public IEnumerable<CWRecords> PastRecordObj { get; set; }
}
}
I have a strong believe that I am doing something wrong in the Controller.
//POST : Services/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(CWandRecordsViewModel model)
{
if (ModelState.IsValid)
{
{
model.NewRecordObj.CWId = model.CWId;
model.NewRecordObj.DateAdded = DateTime.Now;
_db.Add(model.NewRecordObj);
await _db.SaveChangesAsync();
};
using (var memoryStream = new MemoryStream())
{
await model.Document.CopyToAsync(memoryStream);
};
return RedirectToAction(nameof(Create), new { CWId = model.CWId });
}
var CW = _db.ContingentWorkers.FirstOrDefault(c => c.Id == model.CWId);
var newModel = new CWandRecordsViewModel
{
CWId = CW.Id,
Title = CW.Title,
FullNames = CW.FullNames,
Surname = CW.Surname,
DateofBirth = CW.DateofBirth,
IdPassportNumber = CW.IdPassportNumber,
Gender = CW.Gender,
Race = CW.Race,
Nationality = CW.Nationality,
PastRecordObj = _db.CWRecords.Where(r => r.CWId == model.CWId).OrderByDescending(r => r.DateAdded).Take(5)
};
return View(newModel);
}
How can i fix the controller so that i can upload the file onto the database.
First of all, you should not have the new entity that you want to create as a property inside of your view model. You should have those separated and only create the entity when you are actually creating it.
Then, in order to store the data from the uploaded file, you will have to store it inside of your entity. Right now, all you are doing is copying the data from the uploaded file into a memory stream. And then you discard the memory stream, so all the data is lost and never reaches the entity or the database (the database changes are also saved before you read the file).
Your code should look something like this:
if (ModelState.IsValid)
{
var newRecordObj = new CWRecords
{
CWId = model.CWId,
DateAdded = DateTime.Now,
};
using (var memoryStream = new MemoryStream())
{
await model.Document.CopyToAsync(memoryStream);
newRecordObj.Document = memoryStream.ToArray();
};
_db.Add(newRecordObj);
await _db.SaveChangesAsync();
return RedirectToAction(nameof(Create), new { CWId = model.CWId });
}

Angular 2 to post data to asp.net mvc controller

I am trying to post data from angularjs2 to asp.net mvc controller.
The actual issue is that when I am trying with it then
See how am I trying ?
this is the typescript ---
save(company: Company): Observable<boolean> {
let headers = new Headers({ 'Content-Type': 'application/json' });
this._http.post(this._postUrl, /*JSON.stringify(*/company/*)*/, { headers: headers })
.subscribe(
(data) => {
console.log('Response');
new Observable<true>()
},
(err) => { console.log(err); new Observable<false>(); },
() => console.log('Complete')
);
return new Observable<false>();
}
onSignUpClicked(message: string): void {
this._service.save(this.company).subscribe(
res => console.log(res),
error => this.errorMessage = <any>error
);
this is the typescript class:
import { Address } from '../shared/Address';
import { Contact } from '../shared/Contact';
export class Entity {
Id: string;
InsertionTime: Date;
InsertUserId: number;
IsDeleted: boolean;
IsLocked: boolean;
UpdateTime: Date;
UpdateUserId: number;
}
export class Company extends Entity {
Name: string;
Address: Address;
Contact: Contact;
Password: string;
ConfirmPassword: string;
UserName: string;
RegistrationDate: Date;
IsActive: boolean;
NextBillingDate: string;
TransactionLimit: number
}
and C# class
public class Company : Entity
{
public string Name { get; set; }
public Address Address { get; set; }
public Contact Contact { get; set; }
public string Password { get; set; }
public string UserName { get; set; }
public Image LogoImage { get; set; }
public DateTime RegistrationDate { get; set; }
public DateTime LastUpdated { get; set; }
public bool IsActive { get; set; }
public DateTime NextBillingDate { get; set; }
public Int64 TransactionLimit { get; set; }
}
public class Entity : IEntity
{
public Entity()
{
Id = Guid.NewGuid();
InsertionTime = DateTime.Now;
IsDeleted = false;
IsLocked = false;
}
public Guid Id
{
get;set;
}
public DateTime InsertionTime
{
get;set;
}
public int InsertUserId
{
get; set;
}
public bool IsDeleted
{
get; set;
}
public bool IsLocked
{
get; set;
}
public DateTime? UpdateTime
{
get;set;
}
public int? UpdateUserId
{
get; set;
}
}
any help appreciated
Here is a basic call to the server from an ng2 app:
getMeSomeServerData(someVar: string): Promise < IGenericRestResponse > {
let headers = new Headers();
headers.append("Content-Type", "application/json");
let url = "/getMeSomeServerData";
let post = this.http.post(url, JSON.stringify(someVar), {
headers: headers
}).map(response => response.json());
return post.toPromise();
}
And on the asp.net mvc backend:
// this of course goes within a controller
[HttpPost()]
[Route("getMeSomeServerData")]
public JsonNetResult GetMeSomeServerData(string someVar) {
GenericRestResponse response = new GenericRestResponse();
response.Error = false;
// do somthing
return new JsonNetResult(response);
}
JsonNetResult is simply a custom method for serializing an object into json. Obviously, you can modify someVar and IGenericRestResponse to your own needs.
On the client side, you also can return an Observable instead of a promise; the promise method is more familiar to me, so I use it unless I need some of the special functionality of an Observable.

Categories

Resources