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

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.

Related

custom response object for model validation in asp.net core

I want custom object in response of API having [required] data annotation on model properties like this:
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "fatal",
"code": "required",
"location": [
"/f:AllergyIntolerance/f:status"
]
}
]
}
Is it possible to do it or I would have to code it.
Because model validation happens before action is called, is there any way I can do it?
To create custom request and respond samples for your api, you can use Swashbuckle.AspNetCore.Swagger and to improve validations on your models you can use FluentValidations Sample. Good Luck!
first for simplify define your models like these :
public class ResponseModel
{
public string resourceType { get; set; }
public List<ResponseIssueModel> issue { get; set; } = new List<ResponseIssueModel>();
}
public class ResponseIssueModel
{
public string severity { get; set; }
public string code { get; set; }
public List<string> locations { get; set; } = new List<string>();
}
Then on your actions you can return this :
var response = new ResponseModel();
response.resourceType = "OperationOutcome";
response.issue.Add(new ResponseIssueModel
{
severity = "fatal",
code = "required",
locations = { "/f:AllergyIntolerance/f:status" }
});
return Ok(response);
you can use Builder Pattern for easy create response object
If you want to validate your model in controller,you could try with TryValidateModel method as mentioned in the document:
I tried as below:
in controller:
var model = new TestModel() { Id=1,nestedModels=new List<NestedModel>() { new NestedModel() { Prop1="P11"} } };
var isvalid=TryValidateModel(model);
var errorfiledlist = new List<string>();
if (!isvalid)
{
foreach (var value in ModelState.Values)
{
foreach (var error in value.Errors)
{
errorfiledlist.Add(MidStrEx(error.ErrorMessage,"The "," field"));
}
}
}
var jsonstring = JsonSerializer.Serialize(model);
foreach (var field in errorfiledlist)
{
var oldstr = String.Format("\"{0}\":null", field);
var newstr = String.Format("\"{0}\":\"required\"", field);
jsonstring = jsonstring.Replace(oldstr, newstr);
};
var obj = JsonSerializer.Deserialize<Object>(jsonstring);
return Ok(obj);
MidStrEx method:
public static string MidStrEx(string sourse, string startstr, string endstr)
{
string result = string.Empty;
int startindex, endindex;
try
{
startindex = sourse.IndexOf(startstr);
if (startindex == -1)
return result;
string tmpstr = sourse.Substring(startindex + startstr.Length);
endindex = tmpstr.IndexOf(endstr);
if (endindex == -1)
return result;
result = tmpstr.Remove(endindex);
}
catch (Exception ex)
{
}
return result;
}
Models:
public class TestModel
{
public int Id { get; set; }
[Required]
public string Prop { get; set; }
public List<NestedModel> nestedModels { get; set; }=new List<NestedModel>();
}
public class NestedModel
{
public string Prop1 { get; set; }
[Required]
public string Prop2 { get; set; }
}
The result:

How to determine whether a model is valid?

I am having some trouble here. The situation is to update an existing record, at the same time, save a new row if there is no record by searching first the table.
When I am saving a new record, there is no problem. But when I'm trying to update an existing one, there are no changes. I tried to place some breakpoints specifically on the code that do the thing. It just ending up on the line if(!ModelState.IsValid).
Note:
Some of the lines are hard-coded for the sake of having some dummy data.
Function for retrieving some data from DB to pass to view model
[HttpGet]
public ActionResult CardNumberAssignment(string empId, int cardNumberId)
{
var getIdDetails = dbContext.CardNumberAssignments.Where(c => c.CardNumberId == cardNumberId && c.IsActive == true).SingleOrDefault();
if (cardNumberId == 0) //EMPLOYEE HAS NO CARD NUMBER YET
{
var viewModel = new CardNumberQRCodeVM
{
CardNumberId = 0,
CMId = empId,
OldQRCode = "No QR Code history",
OldReservedCardNumber = "No Card Number history",
NewReservedCardNumber = GetRandomCardNumber()
};
return View(viewModel);
}
else
{
if (getIdDetails.CMId != empId) //JUST CHECKING IF THE EMPLOYEE HAS THE CORRECT CARDNUMBERID FROM DB
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var empCardDetails = dbContext.CardNumberAssignments
.Include(c => c.ReservedCardNumber)
.Where(emp => emp.CMId == empId && emp.IsActive == true)
.Select(fields => new CardNumberQRCodeVM
{
CardNumberId = fields.CardNumberId,
CMId = empId,
OldQRCode = fields.QRCode,
IsActive = fields.IsActive,
OldReservedCardNumber = fields.ReservedCardNumber.CardNumber,
}).FirstOrDefault();
empCardDetails.NewReservedCardNumber = GetRandomCardNumber();
return View(empCardDetails);
}
}
Function for adding/editing record
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SaveIdInformation(CardNumberQRCodeVM vm)
{
if (!ModelState.IsValid)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
// JUST ADDING/EDITING SOME CARD NUMBERS....
else
{
if (vm.CardNumberId == 0) //INSERT A NEW ROW FOR NEW CARD NUMBER AND QR CODE
{
var newCardNumber = new ReservedCardNumber
{
CardNumber = vm.NewReservedCardNumber,
IsActive = true,
CreatedDate = DateTime.Now,
CreatedBy = "Paolo",
ModifiedDate = DateTime.Now,
ModifiedBy = "Paolo"
};
dbContext.ReservedCardNumbers.Add(newCardNumber);
var newIdInfo = new CardNumberAssignment
{
CardNumberId = newCardNumber.Id,
QRCode = vm.NewQRCode,
CMId = vm.CMId,
IsActive = true,
CreatedDate = DateTime.Now,
CreatedBy = "Paolo",
ModifiedDate = DateTime.Now,
ModifiedBy = "Paolo"
};
dbContext.CardNumberAssignments.Add(newIdInfo);
}
else // EDIT EXISTING
{
var getEmployeeIdInDb = dbContext.CardNumberAssignments.Single(e => e.Id == vm.CardNumberId);
getEmployeeIdInDb.ReservedCardNumber.CardNumber = vm.NewReservedCardNumber;
getEmployeeIdInDb.QRCode = vm.NewQRCode;
getEmployeeIdInDb.IsActive = true;
getEmployeeIdInDb.ModifiedDate = DateTime.Now;
getEmployeeIdInDb.ModifiedBy = "Paolo";
}
dbContext.SaveChanges();
}
return RedirectToAction("CMDetails", "Admin", new { #empId = vm.CMId });
}
View model
public class CardNumberQRCodeVM
{
public int CardNumberId { get; set; }
public string CMId { get; set; }
[Display(Name = "Existing QR Code")]
public string OldQRCode { get; set; }
[Required]
[Display(Name = "New QR Code")]
public string NewQRCode { get; set; }
[Display(Name = "Resigned Cast Member?")]
public bool IsActive { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedDate { get; set; }
public string ModifiedBy { get; set; }
public DateTime ModifiedDate { get; set; }
public ReservedCardNumber ReservedCardNumber { get; set; }
[Display(Name = "Old Card Number")]
public string OldReservedCardNumber { get; set; }
[Display(Name = "New Card Number")]
public string NewReservedCardNumber { get; set; }
}

how to construct url for image saved in database

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

How can I add another parameter to a drop down box?

At the moment I have a drop down box which only displays a Suppliers Name with the value of the ID hidden behind it. I would also like to display the Suppliers account number next to the Supplier Name.
HTML:
#Html.DropDownListFor(
m => m.SupplierID,
new SelectList(Model.Suppliers, "SupplierID", "SupplierName"),
new { #id = "SuppNameDD", #class = "GRDropDown" }
)
Controller:
public ActionResult Index(string client) {
int clientID = clientRepo.GetClientIDByName(client);
DashboardViewModel model = new DashboardViewModel();
model.ClientID = clientID;
model.ClientName = client;
model.FinancialsAtAGlance = reportRepo.GetFinancialsAtAGlance(model.ClientID);
model.SupplierID = -1;
model.AccountNo = null;
model.Suppliers = supplierRepo.GetAllSuppliersByClient(clientID);
model.ReviewID = -1;
model.AccountNo = null;
model.Reviews = reviewRepo.GetAllReviewsByClientID(clientID);
return View(model);
}
ViewModel:
public class DashboardViewModel {
public int ClientID { get; set; }
public string ClientName { get; set; }
public IQueryable<FinancialsAtAGlanceModel> FinancialsAtAGlance { get; set; }
public Dictionary<string, Dictionary<string, decimal?>> Budgets { get; set; }
public class SelectReport {
public int ReportID { get; set; }
public string ReportType { get; set; }
public static IEnumerable<SelectReport> Reports = new List<SelectReport> {
new SelectReport {
ReportID = 1,
ReportType = "Claims By Supplier"
},
new SelectReport {
ReportID = 2,
ReportType = "Department breakdown"
},
new SelectReport {
ReportID = 3,
ReportType = "Reason Code breakdown"
},
new SelectReport {
ReportID = 4,
ReportType = "Monthly Debiting report"
}
};
}
public List<SelectReport> allReports { get; set; }
public int SupplierID { get; set; }
public IEnumerable<Supplier> Suppliers { get; set; }
public int ReviewID { get; set; }
public string AccountNo { get; set; }
public IEnumerable<Review> Reviews { get; set; }
}
How can add this is as the other value is a selected value and this is not what I want. It should be another datatext field.
If this display name is something that would be used multiple times, I would suggest adding a property to your Supplier class. Something like DisplayName:
public class Supplier
{
//...
public string SupplierName { get; set; }
public string AccountNumber { get; set; }
//...
public string DisplayName
{
get { return String.Format("{0} ({1})", SupplierName, AccountNumber); }
}
}
Then, you just need to change your drop down list to use DisplayName instead of SupplierName as the text field:
#Html.DropDownListFor(m => m.SupplierID, new SelectList(Model.Suppliers, "SupplierID", "DisplayName"), new { #id = "SuppNameDD", #class = "GRDropDown" })
EDIT:
There is another way to do this that can be done all in the view:
#Html.DropDownListFor(m => m.SupplierID, Model.Suppliers.Select(item => new SelectListItem
{
Value = item.SupplierID.ToString(),
Text = String.Format("{0} ({1})", item.SupplierName, item.AccountNumber.ToString()),
Selected = item.SupplierID == Model.SupplierID
}))
Probably you can achieve your desired output by 1.create a custom helper with with extension method which will return MvcHtmlString which will create your custom HTML for dropdown and call that method in your view.
Like Below
public static class CustomDropdown
{
public static string Dropdown(Priority priority)
{
StringBuilder sb=new StringBuilder ();
sb+="<Select id='drop'>";
for(int i=0;i<priority.name.length;i++)
{
sb+="<option id='dropop' value='"+priority.value[i]+"'title='"+priority.title[i]+"'>"+priority.name[i]+"</option>";
}
sb+="</select>";
return Convert.ToString(sb);
}
}
2.Bind the options of the given select with help of jquery like
var i=0;
$('.drpclass option').each(function(){
$(this).attr('title',Model.priority.title[i])
i++;
});

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