how to construct url for image saved in database - c#

I am running into a problem. I have my database properly configured and image is saving in database properly but dont know how to construct url for the image saved in database as i have to supply it to the knockout view model for binding.
public JsonResult GetPosts()
{
var ret = (from post in db.Posts.ToList()
orderby post.PostedDate descending
select new
{
Message = post.Message,
PostedBy = post.PostedBy,
PostedByName = post.ApplicationUser.UserName,
// having problem at this line dont know how to construct url at this line as i have to supply url
// (String type to the PostedByAvatar)
PostedByAvatar = db.Files.SingleOrDefault(s => s.ApplicationUserId == post.PostedBy),
PostedDate = post.PostedDate,
PostId = post.PostId,
}).AsEnumerable();
return Json(ret, JsonRequestBehavior.AllowGet);
}
this is the knockout function--------
function Post(data) {
var self = this;
data = data || {};
self.PostId = data.PostId;
self.Message = ko.observable(data.Message || "");
self.PostedBy = data.PostedBy || "";
self.PostedByName = data.PostedByName || "";
self.PostedDate = getTimeAgo(data.PostedDate);
self.PostedByAvatar = data.PostedByAvatar || "";
self.error = ko.observable();
self.PostComments = ko.observableArray();
and this is the view model to get the existing post, comment etc with image from the database-----
function viewModel() {
var self = this;
self.posts = ko.observableArray();
self.newMessage = ko.observable();
self.error = ko.observable();
self.loadPosts = function () {
// to load existing posts
$.ajax({
url: postApiUrl1,
datatype: "json",
contentType: "application/json",
cache: false,
type: 'Get'
})
and on my view page, this the container box to load the image with post-----
<ul id="msgHolder" data-bind="foreach: posts">
<li class="postHolder">
<img data-bind="attr: { src: PostedByAvatar }">
<p><a data-bind="text: PostedByName"></a>: <span data-bind=" html: Message"></span></p>
Now, the model class which saves the image in database is something like this.It has ApplicationUserId as foreign key pointing to ApplicationUserClass---
public class File
{
[Key]
public int FileId { get; set; }
[StringLength(255)]
public string FileName { get; set; }
[StringLength(100)]
public string ContentType { get; set; }
public byte[] Content { get; set; }
public FileType FileType { get; set; }
public int ApplicationUserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
}
and ApplicationUserClass is something like this---
public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
public ApplicationUser()
{
this.Posts = new HashSet<Post>();
this.Files = new HashSet<File>();
}
public virtual ICollection<File> Files { get; set; }
public virtual ICollection<Post> Posts { get; set; }
This is the image saved in database.Now, i want to know how to construct url for the image saved in the database as i have to supply it to the view model in string form. or there is any approach better than this.
This is my Post class which have many to one relationship with ApplicationUser class and foreign key is PostedBy pointing the ApplicationUser Class----
public class Post
{
public Post()
{
this.PostComments = new HashSet<PostComment>();
}
[Key]
public int PostId { get; set; }
public string Message { get; set; }
public int? PostedBy { get; set; }
public System.DateTime PostedDate { get; set; }
public virtual ICollection<PostComment> PostComments { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
}

Although it is possible to pass a Base64 string as the src of the <img>, I think the most sensible way would be to not return the actual bytes from the Ajax call but rather create a url that will request the image bytes from the server.
First, add the required Action that will serve the image data:
[HttpGet]
public FileResult GetFileData(int fileId)
{
var file = db.Files.Single(x => x.FileId == fileId);
return File(file.Content, file.ContentType);
}
Now, change your GetPosts action to return url in the PostedByAvatar property:
public JsonResult GetPosts()
{
var ret = (from post in db.Posts.ToList()
orderby post.PostedDate descending)
select new
{
Message = post.Message,
PostedBy = post.PostedBy,
PostedByName = post.ApplicationUser.UserName,
PostedByAvatar = _GenerateAvatarUrlForUser(post.PostedBy),
PostedDate = post.PostedDate,
PostId = post.PostId,
});
return Json(ret, JsonRequestBehavior.AllowGet);
}
private string _GenerateAvatarUrlForUser(int? userId)
{
if (!user.HasValue)
return null;
var avatarImage = db.Files.SingleOrDefault(s => s.ApplicationUserId == userId);
if (avatarImage != null)
return Url.Action("GetFileData", new { fileId = avatarImage.FileId });
return null;
}

Related

Not posting data to an action with MVC(HTTP 415)

I'm looking to send the following fields to a MVC action
public class AddProductViewModel
{
public string ProductId { get; set; }
public string ProductName { get; set; }
public int Quantity { get; set; }
public double Price { get; set; }
public bool Enabled { get; set; }
public List<CategorySelectModel> Categories { get; set; } = new List<CategorySelectModel>();
public List<IFormFile> Photos { get; set; } = new List<IFormFile>();
}
CategorySelectModel:
public string CategoryId { get; set; }
public string CategoryName { get; set; }
and I haved used what i believe represents the actual json data...but I dont get why it isnt posting the data to the action
here is the js code where I have serialized the data and send to the controller
function SubmitProducts(element)
{
element.preventDefault();
let ulContainer = document.getElementById("dropDownAndSel").getElementsByTagName('ul')[0];
var Categories = [];
let x = document.getElementById("dropDownCategories");
for (let i = 0; i < x.children.length; i++) {
if (x.options[i].selected) {
let CategoryName = x.options[i].innerHTML;
let CategoryId = x.children[i].value;
let dropdownItems = { CategoryId, CategoryName };
if (!Categories.includes(dropdownItems)) {
Categories.push(dropdownItems);
}
}
}
let pId = document.getElementById('pId').value;
let ProductId = pId;
let ProductName = document.getElementById('ProductName').value;
if (!ProductName || ProductName.length ==0) {
alert('ProdutName cannot be null or empty');
return;
}
let priceStr = document.getElementById('productPriceId').value;
if (!priceStr || priceStr.length == 0) {
alert('Price cant be empty')
return;
}
let Price = parseFloat(priceStr);
let QuantityStr = document.getElementById('qtyNum').value;
if (!QuantityStr || QuantityStr.length==0) {
alert('Quantity cant be empty');
return;
}
let Quantity = parseInt(QuantityStr);
var formData = new FormData();
let filesContainer = document.getElementById('photoProduct_0');
for (let i = 0; i < filesContainer.files.length; i++) {
formData.append('model.Photos', filesContainer.files[i], filesContainer.files[i].name);
}
formData.set('model.ProductId', ProductId);
formData.set('model.ProductName', ProductName);
formData.set('model.Price', Price);
formData.set('model.Quantity', Quantity);
formData.set('model.Categories', JSON.stringify(Categories));
$.ajax({
url: '/' + 'Product' + '/' + 'AddProduct',
type: 'POST',
contentType: false,
processData: false,
data: formData,
success: console.log('success'),
});
}
Here is the action signature:
[HttpPost]
public async Task<IActionResult> AddProduct([FromBody] AddProductViewModel model)
Code above post FormData data. Therefore, the AddProductViewModel parameter should be bound using form-data in the request body:
[HttpPost]
public async Task<IActionResult> AddProduct([FromForm] AddProductViewModel model)
Reference to the following post: ASP.NET Core form POST results in a HTTP 415 Unsupported Media Type response

ASP.NET C# inserting multiple values in single field in MongoDB

I am trying to store names of team members of a project in the same field in MongoDB using ASP.NET.
The value is read correctly but I am having trouble creating a new entry.
Below is my controller. Simply writing the document.insert() doesn't work as it only stores a single value and not a list.
public ActionResult InsertProject(Projectdata model)
{
_dbContext = new MongoContext();
if (Request.Cookies["Userdata"] == null)
{
return this.RedirectToAction("Index", "User");
}
var document2 = _dbContext._database.GetCollection<Mongodata>("mainuser_data");
var users = document2.FindAll().ToList();
var document = _dbContext._database.GetCollection<ProjectItem>("project_data");
string project = model.pname;
var query = Query<ProjectItem>.EQ(model2 => model2.pname, project);
var count = document.FindAs<ProjectItem>(query).Count();
if (count == 0)
{
var result = document.Insert(model);
TempData["Message"] = "Project Added";
return View();
}
else
{
TempData["Message"] = "Project Already Exists";
return View("Insert", model);
}
}
My model:
public class Projectdata
{
[BsonId]
public ObjectId Id { get; set; }
[BsonElement("pname")]
public string pname { get; set; }
[BsonElement("pdesc")]
public string pdesc { get; set; }
[BsonElement("sdate")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MMM/yyyy}")]
public DateTime sdate { get; set; }
[BsonElement("edate")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MMM/yyyy}")]
public DateTime edate { get; set; }
public List<Team2> teams { get; set; }
[BsonElement("leader")]
public string leader { get; set; }
}
public class Team2
{
[BsonElement("username")]
public string username { get; set; }
}
I can read all multiple values fine but creating a new entry is where I am facing trouble.
Below is the sample data to be added:
{
"_id" : ObjectId("5f93cf48a591c562654d4ded"),
"pname" : "demo1",
"pdesc" : "this is a demo project",
"sdate" : "24-10-2020",
"edate" : "25-10-2020",
"teams" : [
{
"username" : "ManushPandya"
},
{
"username" : "KuntalVakil"
}
],
"leader" : "ManushPandya"
}
How do I store multiple values in teams field? I am using check boxes to let user select those multiple values in a view.

How send image as byte array from Angular 9 to C# Web API Core, like are property of object? CRUD Client aplication with image

Frontend - Angular 9
Backend - ASP.NET Core Web API
/
Middleware Entity Framework 6.0
/
MS SQL SERVER
I don't know what type of object property I must set in Angular?
How I can add an image to my object and send them to Web Api?
How I can show them back in Angular app?
Web API Controller POST:
[HttpPost]
public async Task<ActionResult<Leaks>> PostLeaks(Leaks leaks)
{
// DateTime and Username implemented to backend
DateTime curDate = DateTime.Now;
leaks.Date = curDate;
var currentUser = HttpContext.User;
string userLastname = currentUser.Claims.FirstOrDefault(c => c.Type == "lastname").Value;
leaks.Repairer = userLastname;
//
_context.Leaks.Add(leaks);
await _context.SaveChangesAsync();
return CreatedAtAction("GetLeaks", new { id = leaks.Id }, leaks);
}
Leaks.cs:
public partial class Leaks
{
public int Id { get; set; }
public string Sn { get; set; }
public string ShiftSmt { get; set; }
public string ShiftMi { get; set; }
public string Location { get; set; }
public DateTime? Date { get; set; }
public string Repairer { get; set; }
public string AoiResult { get; set; }
public string OperatorSmt { get; set; }
public string ModelSmt { get; set; }
public string Platform { get; set; }
public string Remark { get; set; }
public string Defect { get; set; }
public byte[] Image { get; set; }
public string Status { get; set; }
public string Side { get; set; }
public string Extra1 { get; set; }
public string Extra2 { get; set; }
}
MS SQL Image data type is varbinary(MAX)
Leaks.component.ts:
// *ngOnInit start
ngOnInit() {
//Selected options loader
this.platformsService.getAllPlatforms()
.subscribe(res => this.platforms = res as []);
this.defectslistService.getAllDefectslist()
.subscribe(res => this.defect = res as []);
// input form validation
this.leaksForm = this.formbulider.group({
Date:[null],
Sn:[null, [Validators.required]],
ShiftMI:[null, [Validators.required]],
ShiftSMT:[null, [Validators.required]],
Location:[null, [Validators.required]],
Defect:[null, [Validators.required]],
Side:[null, [Validators.required]],
AoiResult:[null],
Platform:[null, [Validators.required]],
ModelSMT:[null],
OperatorSMT:[null],
Repairer:[null],
Image:[null],
Remark:[null],
Status:[null, [Validators.required]],
});
// *load all data from Database*
this.loadallLeaks();
this.toastr.info("Init Successfully Done");
//*Angular mat-table*
this.leaksService.getAllLeaks().subscribe(list => {
let array = list.map(item => {
return { ...item };
});
this.listData = new MatTableDataSource(array);
this.listData.sort = this.sort;
this.listData.paginator = this.paginator;
this.isLoading = false;
});
//*Angular mat-table end*
}
// *ngOnInit end*
loadallLeaks() {
this.allLeaks = this.leaksService.getAllLeaks();
this.leaksService.getAllLeaks().subscribe(res => {
this.dataSource = new MatTableDataSource(res);
})
this.toastr.info("Data Was Successfully Loaded");
}
onFormSubmit() {
this.dataSaved = false;
const leaks = this.leaksForm.value;
this.CreateLeaks(leaks);
this.leaksForm.reset();
}
loadLeaksToEdit(leaksId: string) {
this.leaksService.getLeaksById('/'+leaksId).subscribe(leaks=> {
this.massage = null;
this.dataSaved = false;
this.leaksIdUpdate = leaks.Id;
this.leaksForm.controls['Sn'].setValue(leaks.Sn);
this.leaksForm.controls['Date'].setValue(leaks.Date);
this.leaksForm.controls['ShiftSMT'].setValue(leaks.ShiftSMT);
this.leaksForm.controls['ShiftMI'].setValue(leaks.ShiftSMT);
this.leaksForm.controls['Location'].setValue(leaks.Location);
this.leaksForm.controls['Defect'].setValue(leaks.Defect);
this.leaksForm.controls['Side'].setValue(leaks.Side);
this.leaksForm.controls['AoiResult'].setValue(leaks.AoiResult);
this.leaksForm.controls['Platform'].setValue(leaks.Platform);
this.leaksForm.controls['ModelSMT'].setValue(leaks.ModelSMT);
this.leaksForm.controls['OperatorSMT'].setValue(leaks.OperatorSMT);
this.leaksForm.controls['Remark'].setValue(leaks.Remark);
this.leaksForm.controls['Repairer'].setValue(leaks.Repairer);
this.leaksForm.controls['Image'].setValue(leaks.Image);
this.leaksForm.controls['Status'].setValue(leaks.Status);
});
}
CreateLeaks(leaks: Leaks) {
if (this.leaksIdUpdate == null) {
this.leaksService.createLeaks(leaks).subscribe(
() => {
this.dataSaved = true;
this.toastr.success("Record Saved Successfully");
this.loadallLeaks();
this.leaksIdUpdate = null;
this.leaksForm.reset();
} );
} else {
leaks.Id = this.leaksIdUpdate;
this.leaksService.updateLeaks(leaks).subscribe(() => {
this.dataSaved = true;
this.toastr.success("Record Updated Successfully");
this.loadallLeaks();
this.leaksIdUpdate = null;
this.leaksForm.reset();
}); }
}
deleteLeaks(leaksId: string) {
if (confirm("Are you sure you want to delete this ?")) {
this.leaksService.deleteLeaksById(leaksId).subscribe(() => {
this.dataSaved = true;
this.toastr.warning("Record Deleted Succefully");
this.loadallLeaks();
this.leaksIdUpdate = null;
this.leaksForm.reset();
}); }
}
resetForm() {
this.leaksForm.reset();
this.massage = null;
this.dataSaved = false;
this.toastr.info("Form Succefully reseted");
}
leaks.ts:
export class Leaks {
Id:number;
Date:string;
Sn:string;
ShiftMI:string;
ShiftSMT:string;
Location:string;
Defect:string;
Side:string;
AoiResult:string;
Platform:string;
ModelSMT:string;
OperatorSMT:string;
Repairer:string;
Image:[];
Remark:string;
Status:string;
}
I would suggest you, use the File property in your C# model. Once you receive the image at backend (API) then convert it into the byte array and save it as where ever you want. I believe the trickiest part will be sending the image and the other properties from your angular application to Web API.
Here is an example. In your c# model
public partial class Leaks
{
// existing properties.
public IFormFile Image { get; set; }
}
Make sure you add using Microsoft.AspNetCore.Http; namespace in your class.
Angular application
export class Leaks {
// existing properties.
Image:File;
Remark:string;
Status:string;
}
I believe you must have fileupload in your html so for that you need to add onChange() event and assign file to Image property of your model or just create a variable in your componenet ex uploadedFile
fileChange(fileInputEvent: any) {
this.uploadedFile = fileInputEvent.target.files[0];
}
Now on onFormSubmit()
onFormSubmit() {
this.dataSaved = false;
const leaks = this.leaksForm.value;
leaks.Image = this.uploadedFile
this.CreateLeaks(leaks);
this.leaksForm.reset();
}
and for sending to server just create formdata object fill all properties as you declared in your backend object.
const formData = new FormData();
formData.append('Image', Leaks.Image, Leaks.Image.name);
formData.append('Remark', Leaks.Remarks);
-- and more properties
return this.httpClient.post<boolean>(url, formData);
In your API
[HttpPost]
public async Task<ActionResult<Leaks>> PostLeaks([FromForm]Leaks leaks)
{
// you must receive the file in leaks.Image.
// your logic to convert file to bytes.
}
I hope it helps.

ModelState Error c# mvc5

In an Action Result that does a HttpPost i get an error from EF
"ModelState.Errors Internal error in the expression evaluator"
My model in View is OrdineOmaggio
public partial class OrdineOmaggio
{
public int Id { get; set; }
public string Id_Gioielleria { get; set; }
public System.DateTime Data_Ordine { get; set; }
public virtual Consumatore MD_CONSUMATORE { get; set; }
public virtual Omaggio MD_OMAGGIO { get; set; }
public virtual CodiceRandomConsumatore MD_RANDOM_CONSUMATORE { get; set; }
}
My Action is so
public async Task<ActionResult> ChooseGift(
[Bind(Include ="Data_Ordine,MD_RANDOM_CONSUMATORE,MD_OMAGGIO,Id_Gioielleria")]
OrdineOmaggio ordineOmaggio,
string codiceOmaggio, string codice)
{
var randomConsumatore = _context.CodiciRandomConsumatori
.SingleOrDefault(c => c.Codice == codice) ??
new CodiceRandomConsumatore
{
Id = -1,
Codice = "",
Assegnato = null,
Distinzione = ""
};
var consumatore = _context.CodiciRandomConsumatori
.Where(c => c.Codice == codice)
.Select(c => c.MD_CONSUMATORE)
.SingleOrDefault();
var omaggio = _context.Omaggi
.SingleOrDefault(c => c.CodiceOmaggio == codiceOmaggio);
if (ModelState.IsValid)
{
ordineOmaggio.Data_Ordine = DateTime.Now;
ordineOmaggio.Id_Gioielleria = ordineOmaggio.Id_Gioielleria;
ordineOmaggio.MD_CONSUMATORE = consumatore; // FK
ordineOmaggio.MD_OMAGGIO = omaggio; // FK
ordineOmaggio.MD_RANDOM_CONSUMATORE = randomConsumatore; // FK
_context.OrdiniOmaggio.Add(ordineOmaggio);
randomConsumatore.Assegnato = true;
_context.SaveChanges();
return RedirectToAction("Success");
}
return View(ordineOmaggio);
}
The error is about dataAnnotation: it say that not all field all filled
The metadata is
public class OrdineOmaggioMetadata
{
[Required(ErrorMessage = "Scegli la gioiellereia.")]
public string Id_Gioielleria;
[Required(ErrorMessage = "Seleziona una foto.")]
public Omaggio MD_OMAGGIO;
...
}
In my view i placed
#Html.HiddenFor(m=> m.MD_OMAGGIO.CodiceOmaggio)
#Html.ValidationMessageFor(m => m.MD_OMAGGIO.CodiceOmaggio)
but this helper pass null to ActionResult
MD_OMAGGIO is a table foreign key for product codes.
what i wrong ?

Request.CreateResponse returns blank data to postman

I have encountered a problem when trying to call my web api with a post request, a empty array is returned.
My method is:
// POST: Api/v1/transaction/
[HttpPost]
public HttpResponseMessage Post(string user)
{
var userId = new Guid(user);
var transactions = new Collection<TransactionDataTransferObject>();
try
{
var seller = _databaseContext.Sellers.Single(s => s.Id == userId);
var sellerMedias = _databaseContext.Medias.Where(m => m.TakenBy.Id == seller.Id);
foreach (var sellerMedia in sellerMedias)
{
var allLogsForMedia = _databaseContext.Logs.Where(l => l.ObjectReferenceId == sellerMedia.Id);
foreach (var logMedia in allLogsForMedia)
{
var transaction = new TransactionDataTransferObject
{
Date = logMedia.DateTimeInUtc,
Amount = sellerMedia.PriceInSek,
MediaName = sellerMedia.FileName,
UserName = seller.FirstName + " " + seller.LastName
};
transactions.Add(transaction);
}
}
}
catch (Exception exception)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, exception);
}
return Request.CreateResponse(HttpStatusCode.OK, transactions);
}
When I debug transactions variable, I see two objects in the collection.
My response to postman is
[
{},
{}
]
What have I done wrong? Where is my data which is sent?
Ok, after some hours of slaming my head in the table i found out that I used
[DataContract] as filter on the ViewModel,TransactionDataTransferObject.
Like this:
[DataContract]
public class TransactionDataTransferObject
{
[Display(Name = "Date")]
public DateTime Date { get; set; }
public string MediaName { get; set; }
public Guid MediaId { get; set; }
public string UserName { get; set; }
public Guid UserId { get; set; }
[Display(Name = "Description")]
public string Discriminator { get; set; }
[Display(Name = "Amount")]
public decimal Amount { get; set; }
}
Which was wrong in this case...
Thanks for reading!

Categories