large file attachment via Angularjs - javascript

Below code has been generated and connected to a controller called "streaming" in .net core. The code works well and attaches large files perfectly.
The code needs to be used in another html page to upload files for different purpose. However, when upload button is pressed, below error is displayed:
Failed to load resource: the server responded with a status of 400 (Bad Request)
This is the case that if I attach a file from the original page, the process gets completed and then I can attach any file from the copied page!
But if I close the browser and try to attach a file from the copied page the error is displayed.
<div class="panel-body" ng-app="myApp">
#*Attachment*#
<div ng-app="myApp">
<div ng-controller="myCtrl">
<div>
#if (ViewBag.Attachments != null)
{
foreach (var a in ViewBag.Attachments)
{
var id = #a.AttachmentId;
#lastattachid = id;
<div class="row">
<div class="col-xs-12 left">
<a asp-action="Download" asp-route-path="#a.FilePath\\#a.FileName">#a.FileName</a>
<div style=" position: absolute;top: 2px;right: 2px;">
#if (ViewBag.recepient.Equals(#a.CreatedBy))
{
var FilePath = #a.FilePath.Replace("\\", "\\\\");
<a onclick='deleteattachment(#a.AttachmentId, "#a.FileName", "#FilePath")'>✘</a>
}
</div>
</div>
</div>
}
}
</div>
<hr />
<div>
<div>
<div>
<input name="attachedfile" type="file" file-model="attachedfile" />
</div>
</div>
<br />
<div>
<button ng-click="uploadAttachment()">Upload</button>
</div>
</div>
</div>
</div>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js">
</script>
<script>
var Attachment = (function () {
function Attachment(customer, invoice, name, dwg, attachedfile) {
this.attachmentid = #lastattachid + 1;
this.customer = customer;
this.jobInv = invoice;
this.jobName = name;
this.jobDwg = dwg;
this.path = "\\#ViewBag.customerId\\" + invoice + ";" + name + ";" + dwg + "\\";
this.fileName = attachedfile.name;
this.attachedfile = attachedfile;
}
return Attachment;
}());
var myApp = angular.module('myApp', []);
myApp.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function () {
scope.$apply(function () {
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
myApp.service('attachmentService', ['$http', function ($http) {
this.uploadAttachment = function (attachment) {
var fd = new FormData();
fd.append('AttachmentId', attachment.attachmentid);
fd.append('Customer', attachment.customer);
fd.append('JobInv', attachment.jobInv);
fd.append('JobName', attachment.jobName);
fd.append('JobDwg', attachment.jobDwg);
fd.append('Name', attachment.fileName);
fd.append('Path', attachment.path);
fd.append('attachedfile', attachment.attachedfile);
return $http.post('/Streaming/Upload', fd, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
});
};
}]);
myApp.controller('myCtrl', ['$scope', 'attachmentService', function ($scope, attachmentService) {
$scope.uploadAttachment = function () {
$scope.showUploadStatus = false;
$scope.showUploadedData = false;
var attachment = new Attachment("#customerid","#inv", " ", " ", $scope.attachedfile);
attachmentService.uploadAttachment(attachment).then(function (response) { // success
if (response.status === 200) {
var inv = "#inv";
inv = inv.replace("&", "%26");
var job = "#job";
job = job.replace("&", "%26");
var dwg = "#dwg";
dwg = dwg.replace("&", "%26");
window.location.href = "/Quote/Details/#ViewBag.customerId?quoteno=" + inv;
}
},
function (response) { // failure
$scope.uploadStatus = "Attachment upload failed with status code: " + response.status;
$scope.showUploadStatus = true;
$scope.showUploadedData = false;
$scope.errors = [];
$scope.errors = parseErrors(response);
});
};
}]);
function parseErrors(response) {
var errors = [];
for (var key in response.data) {
for (var i = 0; i < response.data[key].length; i++) {
errors.push(key + ': ' + response.data[key][i]);
}
}
return errors;
}
</script>
Updated:
Server-side code is as below:
[HttpPost]
[DisableFormValueModelBinding]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Upload()
{
if (string.IsNullOrEmpty(userManager.GetUserName(User)))
return RedirectToAction(actionName: "Login", controllerName: "Account");
if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
{
return BadRequest($"Expected a multipart request, but got {Request.ContentType}");
}
// Used to accumulate all the form url encoded key value pairs in the
// request.
var formAccumulator = new KeyValueAccumulator();
string targetFilePath = Directory.GetCurrentDirectory() + "\\wwwroot\\Attachment";
string fileName = "";
var boundary = MultipartRequestHelper.GetBoundary(
MediaTypeHeaderValue.Parse(Request.ContentType),
_defaultFormOptions.MultipartBoundaryLengthLimit);
var reader = new MultipartReader(boundary, HttpContext.Request.Body);
var section = await reader.ReadNextSectionAsync();
while (section != null)
{
ContentDispositionHeaderValue contentDisposition;
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition);
if (hasContentDispositionHeader)
{
if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition))
{
using (var targetStream = System.IO.File.Create(targetFilePath + fileName))
{
await section.Body.CopyToAsync(targetStream);
_logger.LogInformation($"Copied the uploaded file '{targetFilePath + fileName}'");
}
}
else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition))
{
// Content-Disposition: form-data; name="key"
//
// value
// Do not limit the key name length here because the
// multipart headers length limit is already in effect.
var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name);
var encoding = GetEncoding(section);
using (var streamReader = new StreamReader(
section.Body,
encoding,
detectEncodingFromByteOrderMarks: true,
bufferSize: 1024,
leaveOpen: true))
{
// The value length limit is enforced by MultipartBodyLengthLimit
var value = await streamReader.ReadToEndAsync();
value = value.Replace("&", "&");
if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase))
{
value = String.Empty;
}
formAccumulator.Append(key, value);
if (key.Equals("Path"))
{
targetFilePath += value;
Directory.CreateDirectory(targetFilePath);
}
if (key.Equals("Name"))
fileName = value;
if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit)
{
throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded.");
}
}
}
}
// Drains any remaining section body that has not been consumed and
// reads the headers for the next section.
section = await reader.ReadNextSectionAsync();
}
// Bind form data to a model
var attachment = new AttachFile();
var formValueProvider = new FormValueProvider(
BindingSource.Form,
new FormCollection(formAccumulator.GetResults()),
CultureInfo.CurrentCulture);
var bindingSuccessful = await TryUpdateModelAsync(attachment, prefix: "",
valueProvider: formValueProvider);
if (!bindingSuccessful)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
}
var user = userManager.GetUserName(User);
// Add attachmnet to a jason file
// ...
var uploadedData = new UploadedData()
{
Invoice = attachment.JobInv,
Name = attachment.JobName,
Dwg = attachment.JobDwg,
FileName = attachment.FileName,
FilePath = targetFilePath,
CreatedBy = user,
CreatedDate = DateTime.Now
};
return Json(uploadedData);
}
public class AttachFile
{
public int AttachmentId { get; set; }
public string Customer { get; set; }
public string JobInv { get; set; }
public string JobName { get; set; }
public string JobDwg { get; set; }
public string FileName { get; set; }
public string FilePath { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedDate { get; set; }
}
public class UploadedData
{
public string Invoice { get; set; }
public string Name { get; set; }
public string Dwg { get; set; }
public string FileName { get; set; }
public string FilePath { get; set; }
public string Path { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedDate { get; set; }
}

Related

Unable to save to DB, string was not recognized as a valid DateTime MVC

I have two text boxes that are enabled based on a checkbox. If checked == true then enable editing. Until this point everything is fine. However, when I hit the Submit button to save it to the database, it's not working. I was able to save it with just one of the text boxes being editable. Now that I have two editable boxes, it's not working.
Problem:
The ajax call is sending the dates and the ID back to the controller method. However, it's not getting saved to the DB. In UpdatePlannedDate I put in a couple breakpoints, its completely skipping over the first forEach loop.
The Exception it's throwing:
String was not recognized as a valid DateTime.
Model Class:
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime? Date1{ get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime? Date2{ get; set; }
public string R_ID { get; set; }
public string U_ID { get; set; }
public string C_ID { get; set; }
Controller class:
[HttpPost]
public JsonResult UpdatePlannedDate(string ids, string Date1, string Date2)
{
model = new Hello();
Entity db = new Entity();
List<Hello> list = new List<Hello>();
string[] IDS = ids.Split(',');
string[] Date1S = Date1.Split(',');
string[] Date2S = Date2.Split(',');
try
{
for (int i = 0; i < IDS.Length; i++)
{
if (IDS[i] != null && IDS[i] != "")
{
Hello item = new Hello { R_ID = IDS[i], Date_Two = DateTime.Parse(Date2S[i]), Date_One = DateTime.Parse(Date1S[i]) };
list.Add(item);
}
}
foreach (var row in db.table1)
{
foreach (var row2 in db.table2)
{
if (row.U_ID == row2.C_ID)
{
foreach (var item in list)
{
if (row.U_ID == item.R_ID)
{
var cd = db.Table2.Where(x => x.C_ID == row.U_ID).First();
cd.PlanDate = Convert.ToDateTime(item.Date_Two);
cd.PlanDate = Convert.ToDateTime(item.Date_One);
}
}
}
}
}
db.SaveChanges();
return Json(new { success = true, msg = "Updated" });
}
catch (Exception ex)
{
return Json(new { success = false, msg = ex.Message });
}
}
View class:
$(document).ready(function () {
var ids = "";
var date1 = "";
var date2 = "";
//Save to DB
$("#btnSubmit").bind("click", function () {
createUpdateArrays();
var url = "/Sample/UpdatePlannedDate";
$.ajax({
type: "POST",
url: url,
data: { ids: ids, date1: date1, date2: date2 },
success: function (data) {
if (data.success) {
$('.msg').html('Updated');
}
else {
alert("error");
}
}
});
ids = "";
date1 = "";
date2 = "";
});
function createUpdateArrays() {
var i = 0;
$('input.remedy-id:checkbox').each(function () {
if ($(this).is(':checked')) {
var rid = $(this).attr("id");
$('.date2').each(function () {
var did = $(this).attr("id");
if (did === rid) {
var date_2 = $(this).val();
ids += rid + ",";
date2 += date_2 + ",";
}
});
$('.date1').each(function () {
var tid = $(this).attr("id");
if (tid === rid) {
var date_1 = $(this).val();
ids += rid + ",";
date1 += date_1 + ",";
}
});
};
});
};
<tr id="home">
<td><input class="id" type="checkbox" id=#item.R_ID/></td>
<td>#Html.DisplayFor(x => item.R_ID)</td>
<td><input class="date1" id=#item.R_ID type="text" value='#(item.Date1 == null ? "" : Convert.ToDateTime(item.Date1).ToString("MM/dd/yyy"))' readonly="readonly" /></td>
<td><input class="date2" id=#item.R_ID type="text" value='#(item.Date2 == null ? "" : Convert.ToDateTime(item.Date2).ToString("MM/dd/yyy"))' readonly="readonly" /></td>
</tr>
1) What is your ORM? Entity Framework?
2) Try to debug line:
Hello item = new Hello { R_ID = IDS[i], Date_Two = DateTime.Parse(Date2S[i]), Date_One = DateTime.Parse(Date1S[i]) };
3) Isn't datetime conversion twice there?
First Hello item = ... line, second there
cd.PlanDate = Convert.ToDateTime(item.Date_Two);
cd.PlanDate = Convert.ToDateTime(item.Date_One);
4) What will do the change:
cd.PlanDate = item.Date_Two;
cd.PlanDate = item.Date_One;
?
5) Isn't also a logical fault there to have assignation of 2 values to one variable here?
6) Do you have any javascript extension to your fields on side of Razor template? What format it will produce here if you will pick your time from calendar? Does it fits to your definition mask in model class? (
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
)

Can't pass a list of objects to the view using JSON

The data is passed from the controller to the view using AJAX call
but for some reason I am not able to retrieve it using JavaScript
the data shows an list on empty object!
public class Ville {
string wilPop { get; set; }// = null;
int identifiant { get; set; }// = -1;
bool affectedD { get; set; } //= false;
public Ville(string ewilPop, int eidentifiant, bool eaffectedD)
{
this.wilPop = ewilPop;
this.identifiant = eidentifiant;
this.affectedD = eaffectedD;
}
}
[Authorize]
[HttpPost]
public ActionResult GetWilByRegion(int? Wil)
{
if (Wil != null)
{
string wilPop = null;
int identifiant = -1;
bool affectedD = false;
//Get info from DB
List<city> ListWil = new List<city>();
ListWil = db.city.Where(m => m.idReg == Wil).OrderByDescending(m => m.population).ToList();
List<Ville> mylist = new List<Ville>();
foreach (city item in ListWil)
{
// Description in the DB
wilPop = item.city + " (" + item.population + ")";
// id value in the DB
identifiant = item.city_id;
// if checked or not
affectedD = CheckifWilAffected(item.city_id);
mylist.Add(new Ville(wilPop, identifiant, affectedD));
}
return Json(mylist, "Ville");
}
else return Json("Error");
}
mylist is not empty, it contains all the data (after debugging the controller)
This is my AJAX call :
$.ajax({
url: url,
data: { Wil: _idr },
cache: false,
type: "POST",
success: function (data) {
var markup = "";
for (var x = 0; x < data.length; x++) {
markup += '<input type=' + '"checkbox"' + ' name=' + data[x].wilPop + ' value=' + data[x].identifiant + '>' + data[x].wilPop + '</input>' + '<br/>';
}
$("#chWil").html(markup).show();
},
error: function () {
alert("Error - can't do the ajax call - please check your code..." );
}
});
}
You are getting an array of empty objects(without any properties) because your Ville class does not have any public properties.
You need to make your properties public
public class Ville
{
public string wilPop { get; set; }
public int identifiant { get; set; }
public bool affectedD { get; set; }
public Ville(string ewilPop, int eidentifiant, bool eaffectedD)
{
this.wilPop = ewilPop;
this.identifiant = eidentifiant;
this.affectedD = eaffectedD;
}
}
Now the JavaScript serializer will be able to use the values of those properties when creating a JSON string representation of your list.
I personally like to use PascalCasing for class property names.( WilPop instead of wilPop)

validate form before submit asp.net core 2.0

First of all, I am a beginner at this. Have some experience in asp.net, but that i 8 years ago, and a lot has changed since then.
I am sure my problem is quite simple for the experienced developer, I just do not have the experience and knowledge to fix it.
I produce a viewmodel that is passed to a razor view. This view generates a dynamic form, and all that works well. It basically asks a number of questions in groups, and I need to verify that the user has selected an answer for each question before submitting.
A test form looks like this: test form
Each question is created as radio button list, and I need to ensure that all questions has an answer, before it can be submitted.
The current view, which contains a javascript function that works some of the way.. it prevents me from submitting at all.. so looking at something which is not quite right, but has most of it right. So I guess I need a little help to fix that part, or change the way it is done to something better?:
#using RefereeOnline.Models.FormsViewModels
#model RenderFormViewModel
#{
ViewData["Title"] = "Evaluate";
}
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script>
function ValidateForm() {
var isFormValid = true;
$("#evaluateform input,select").each(function () {
var FieldId = "span_" + $(this).attr("id");
if ($.trim($(this).val()).length == 0 || $.trim($(this).val()) == 0) {
$(this).addClass("highlight");
//Show required message along with the field
if ($("#" + FieldId).length == 0) {
$("<span class='error' id='" + FieldId + "'>Required</span>").insertAfter(this);
}
//If you fill and again make the field empty in that case again show the message
if ($("#" + FieldId).css('display') == 'none') {
$("#" + FieldId).fadeIn(500);
}
//$(this).focus();
isFormValid = false;
}
else {
$(this).removeClass("highlight");
if ($("#" + FieldId).length > 0) {
// Hide the message with the fade out effect
$("#" + FieldId).fadeOut(1000);
}
}
});
return isFormValid;
}
</script>
<h2>Evaluate (#Model.FormTitle #Model.FormVersion)</h2>
#using (Html.BeginForm("Evaluate", "Forms", FormMethod.Post, new { id = "evaluateform" }))
{
<div>
<hr />
<dl class="dl-horizontal">
<dt>Name</dt>
<dd>#Model.PersonName</dd>
<dt>Match</dt>
<dd>#Model.ActivityInfo</dd>
<dt>Level</dt>
<dd>#Model.LevelName</dd>
</dl>
<hr />
#for (int g = 0; g < Model.Groups.Count; g++)
{
<table class="table">
#Html.Hidden("Model.Groups[" + #g + "].GroupId", Model.Groups[g].GroupId)
#if (Model.Groups[g].Answers.Any())
{
<tr>
<td></td>
#foreach (var answer in Model.Groups[g].Answers)
{
<td>#answer.Text</td>
}
#if (Model.Groups[g].Questions.Any(x => x.AllowComment))
{
<td>Comment</td>
}
</tr>
}
#for (int i = 0; i < Model.Groups[g].Questions.Count; i++)
{
<tr>
<td>#Model.Groups[g].Questions[i].Text</td>
#if (Model.Groups[g].Answers.Any() && !Model.Groups[g].Questions[i].Answers.Any())
{
foreach (var answer in Model.Groups[g].Answers)
{
<td>
#Html.RadioButton("Model.Groups[" + g + "].Questions[" + i + "].SelectedAnswer", answer.Id)
#Html.Label(answer.Value.ToString(), answer.Value.ToString())
#Html.Hidden("Model.Groups[" + g + "].Questions[" + i + "].FieldId", Model.Groups[g].Questions[i].FieldId)
</td>
}
}
else if (Model.Groups[g].Questions[i].Answers.Any()) //single question with answers
{
foreach (RenderAnswer answer in Model.Groups[g].Questions[i].Answers)
{
<td>
#Html.RadioButton("Model.Groups[" + g + "].Questions[" + i + "].SelectedAnswer", answer.Id)
#Html.Label(answer.Value.ToString(), answer.Text)
#Html.Hidden("Model.Groups[" + g + "].Questions[" + i + "].FieldId", Model.Groups[g].Questions[i].FieldId)
</td>
}
}
else //single question with textbox
{
<td>#Html.TextBox("Model.Groups[" + g + "].Questions[" + i + "].AnswerValue", Model.Groups[g].Questions[i].AnswerValue)</td>
}
#if (Model.Groups[g].Questions.Any(x => x.AllowComment))
{
<td>
#if (Model.Groups[g].Questions[i].AllowComment)
{
#Html.TextArea("Model.Groups[" + g + "].Questions[" + i + "].Comment", Model.Groups[g].Questions[i].Comment, 2, 40, null)
}
</td>
}
</tr>
}
</table>
}
</div>
#Html.Hidden("Model.CustomerId", Model.CustomerId)
#Html.Hidden("Model.FormId", Model.FormId)
#Html.Hidden("Model.UserId", Model.UserId)
#Html.Hidden("Model.ActivityId", Model.ActivityId)
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" onclick="return ValidateForm();" /> |
#Html.ActionLink("Back", "PlannedEvaluations", "Person", new { userid = Model.UserId })
</div>
</div>
}
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
<!--onclick="return ValidateForm();" -->
My view model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace RefereeOnline.Models.FormsViewModels
{
public class RenderFormViewModel
{
public Guid CustomerId { get; set; }
public Guid FormId { get; set; }
public string UserId { get; set; }
public string FormTitle { get; set; }
public string FormVersion { get; set; }
public Guid ActivityId { get; set; }
public string PersonName { get; set; }
public string ActivityInfo { get; set; }
public string LevelName { get; set; }
public List<RenderGroup> Groups { get; set; } = new List<RenderGroup>();
}
public class RenderGroup
{
public string GroupId { get; set; }
public List<RenderQuestion> Questions { get; set; } = new List<RenderQuestion>();
/// <summary>
/// Contains a list of possible answers to limit to
/// If empty, no limited answers
/// </summary>
public List<RenderAnswer> Answers { get; set; } = new List<RenderAnswer>();
}
public class RenderQuestion
{
public Guid FieldId { get; set; }
public string Text { get; set; }
/// <summary>
/// Specific answers for this field
/// Used if in a group, but answers not re-used
/// </summary>
public List<RenderAnswer> Answers { get; set; } = new List<RenderAnswer>();
public string AnswerValue { get; set; }
public Guid SelectedAnswer { get; set; }
public bool AllowComment { get; set; }
public string Comment { get; set; }
}
public class RenderAnswer
{
public Guid Id { get; set; }
public string Text { get; set; }
public int Value { get; set; }
}
}
My controller (has a EF core context), have removed all irrelevant methods:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Rewrite.Internal.UrlActions;
using Microsoft.EntityFrameworkCore;
using RefereeDb.Entities;
using RefereeOnline.Data;
using RefereeOnline.Data.Entities;
using RefereeOnline.Models.FormsViewModels;
using Activity = RefereeOnline.Data.Entities.Activity;
namespace RefereeOnline.Controllers
{
[Authorize]
[Route("[controller]/[action]")]
public class FormsController : Controller
{
private readonly RefereeContext _context;
public FormsController(
RefereeContext context)
{
_context = context;
}
public IActionResult Evaluate(Guid eventid, Guid activityid)
{
var eventData = _context.Events.Find(eventid);
var customer = _context.Customers.Find(eventData.CustomerId);
var activityData = _context.Activities.Include(m => m.MetaData).ThenInclude(f => f.Field)
.ThenInclude(mf => mf.MetaField).Include(l => l.Level).ThenInclude(t => t.Type)
.ThenInclude(r => r.CustomerReferences).First(x => x.Id == activityid);
EvaluationForm form = null;
try
{
form = _context.EvaluationForms.Include(f => f.Fields).ThenInclude(a => a.Answers)
.First(x => x.Id == activityData.Level.Type.CustomerReferences
.First(c => c.CustomerId == customer.Id &&
c.LicenseTypeId == activityData.Level.LicenseTypeId).EvaluationFormId);
}
catch (Exception ex)
{
return RedirectToAction("ShowMessage", "Site",
new
{
message = $"Evaluation forms not configured correctly for {activityData.Level.Name}",
returnurl = HttpUtility.HtmlEncode(Url.Action("Index", "Home"))
});
}
var model = BuildViewModel(form);
model.ActivityId = activityData.Id;
var user = _context.Users.First(x => x.Id == activityData.PersonId);
model.PersonName = user.FullName;
model.LevelName = activityData.Level.Name;
model.ActivityInfo =
$"{activityData.Date.ToShortDateString()} {activityData.Date.ToShortTimeString()} {activityData.Place}";
foreach (CustomerMetaFieldData data in activityData.MetaData.OrderBy(o => o.Field.MetaField.Order))
model.ActivityInfo += $" {data.FieldValue}";
return View(model);
}
[HttpPost]
public IActionResult Evaluate(RenderFormViewModel model)
{
var activity = _context.Activities.Include(l => l.Level).ThenInclude(r => r.Rules).Include(p => p.Person)
.ThenInclude(l => l.Licenses).ThenInclude(t => t.Type).First(x => x.Id == model.ActivityId);
_context.Entry(activity.Person).Collection(x => x.Batches).Load();
//batch id is assigned in post processing
Evaluation evaluation = new Evaluation { ActivityId = activity.Id, EvaluationFormId = model.FormId};
activity.EvaluationData = evaluation;
var customer = _context.Customers.Include(t => t.AssociatedTypes).ThenInclude(s => s.EvaluationSetup)
.First(x => x.Id == model.CustomerId);
var setups = customer.AssociatedTypes.First(t => t.LicenseTypeId == activity.Level.LicenseTypeId)
.EvaluationSetup.Where(x => x.LicenseLevelId == activity.LicenseLevelId);
_context.SaveChanges();
try
{
//load the form
_context.Entry(activity.EvaluationData).Reference(f => f.EvaluationForm).Load();
_context.Entry(activity.EvaluationData.EvaluationForm).Collection(f => f.Fields).Load();
foreach (EvaluationFormField field in activity.EvaluationData.EvaluationForm.Fields)
_context.Entry(field).Collection(a => a.Answers).Load();
Dictionary<string, int> points = new Dictionary<string, int>();
foreach (RenderGroup renderGroup in model.Groups.Where(x => !string.IsNullOrEmpty(x.GroupId)))
{
var groupSetup = setups.FirstOrDefault(x => x.Group == renderGroup.GroupId);
if (renderGroup.GroupId != null)
points.Add(renderGroup.GroupId, 0);
foreach (RenderQuestion question in renderGroup.Questions)
{
activity.EvaluationData.Data.Add(new EvaluationData
{
FieldId = question.FieldId,
AnswerId = question.SelectedAnswer,
EvaluationId = activity.EvaluationData.Id,
Comment = question.Comment
});
if (renderGroup.GroupId != null)
{
var currentField =
activity.EvaluationData.EvaluationForm.Fields.First(f => f.Id == question.FieldId);
FieldAnswer currentAnswer = null;
if (currentField.SameAnswersForAll)
{
var field = activity.EvaluationData.EvaluationForm.Fields.First(x =>
x.Answers.Any() && x.Group == renderGroup.GroupId);
var answers = field.Answers;
currentAnswer = answers.FirstOrDefault(a => a.Id == question.SelectedAnswer);
}
else
{
currentAnswer = currentField.Answers.First(a => a.Id == question.SelectedAnswer);
}
points[renderGroup.GroupId] += currentAnswer.Points;
}
}
if (renderGroup.GroupId != null)
{
var fields =
activity.EvaluationData.EvaluationForm.Fields.Where(x => x.Group == renderGroup.GroupId);
int max = 0;
if (fields.Any(x => x.SameAnswersForAll))
{
max = fields.First(x => x.Answers.Any()).Answers.Max(m => m.Points) * fields.Count();
}
else
{
max = fields.Sum(x => x.Answers.Max(a => a.Points));
}
EvaluationPointSums newPoints =
new EvaluationPointSums
{
GroupId = renderGroup.GroupId,
EvaluationId = evaluation.Id,
Points = points[renderGroup.GroupId],
Threshold = groupSetup?.PassThreshold ?? 0,
Maximum = max
};
evaluation.Points.Add(newPoints);
}
}
_context.Audit.Add(new Audit(User.Identity.Name, evaluation.Id, "Evaluation added"));
_context.SaveChanges();
}
catch (Exception)
{
//reverting the evaluation
_context.Evaluations.Remove(evaluation);
_context.SaveChanges();
//todo: go to message
}
//post processing the evaluation... should new license be created? or expired..
PostProcessEvaluation(activity, evaluation);
return RedirectToAction("EvaluationResult", new { evaluationid = evaluation.Id });
}
public IActionResult EvaluationDetails(Guid activityid, Guid evaluationid, bool score, bool data, string userid)
{
//getting event, activity, metadata, form etc...
var activity = _context.Activities.Include(e => e.EvaluationData).ThenInclude(f => f.EvaluationForm)
.ThenInclude(ff => ff.Fields).ThenInclude(fc => fc.Answers).Include(m => m.MetaData)
.ThenInclude(fd => fd.Field).ThenInclude(d => d.MetaField).Include(e => e.Event).Include(l => l.Level)
.First(x => x.Id == activityid);
_context.Entry(activity.EvaluationData).Collection(x => x.Data).Load();
_context.Entry(activity.EvaluationData).Collection(x => x.Points).Load();
foreach (var evaluationData in activity.EvaluationData.Data)
_context.Entry(evaluationData).Reference(x => x.Answer).Load();
DisplayEvaluationViewModel model = new DisplayEvaluationViewModel { UserId = userid };
model.Activity = activity;
model.RenderModel = BuildViewModel(activity.EvaluationData.EvaluationForm);
return View(model);
}
private void PostProcessEvaluation(Activity activity, Evaluation evaluation)
{
EvaluationRule rule = activity.Person.HasLicense(activity.LicenseLevelId)
? activity.Level.Rules.FirstOrDefault(x => x.Scope == LicenseScope.Licensed)
: activity.Level.Rules.FirstOrDefault(x => x.Scope == LicenseScope.Trainee);
if (rule != null) //if no rule, nothing happens
{
var batch = activity.Person.Batches.FirstOrDefault(x => x.LevelId == activity.LicenseLevelId);
if (batch == null)
{
//creating new batch, marking evaluation with it
batch = new EvaluationIdentityBatch { CurrentBatch = Guid.NewGuid(), LevelId = activity.LicenseLevelId, PersonId = activity.PersonId };
evaluation.BatchId = batch.Id;
activity.Person.Batches.Add(batch);
_context.SaveChanges();
}
//get all evaluations belonging to this batch
var evals = _context.Evaluations.Where(x => x.BatchId == batch.CurrentBatch);
if (evals.Count(x => x.IsPassed) == rule.Goal)
{
//target hit, all is good, execute passed action
ExecuteAction(rule.SuccessAction, activity);
}
else if (evals.Count() == rule.Tries)
{
//execute failed action
ExecuteAction(rule.FailAction, activity);
}
else
{
//log that nothing happens....
Trace.TraceError("Rule found, but not triggered");
}
}
}
private void ExecuteAction(EvalAction action, Activity activity)
{
switch (action)
{
case EvalAction.Issue:
License newLicense = new License
{
Assigned = DateTime.Now,
CustomerId = activity.Person.CustomerId,
LicenseLevelId = activity.LicenseLevelId,
LicenseTypeId = activity.Level.LicenseTypeId,
PersonId = activity.Person.Id,
Recorded = DateTime.Now
};
activity.Person.Licenses.Add(newLicense);
_context.Audit.Add(new Audit(User.Identity.Name, newLicense.Id, "Created by rule"));
break;
case EvalAction.Expire:
var license =
activity.Person.CurrentLicenses.First(x => x.LicenseLevelId == activity.LicenseLevelId);
license.LastActivity = DateTime.Now;
license.ForceExpiry = true;
_context.Audit.Add(new Audit(User.Identity.Name, license.Id, "Expired by rule"));
break;
}
var batch = activity.Person.Batches.First(x => x.LevelId == activity.LicenseLevelId);
activity.Person.Batches.Remove(batch);
_context.SaveChanges();
}
public IActionResult EvaluationResult(Guid evaluationid)
{
EvaluationResultViewModel model = new EvaluationResultViewModel();
var evaluation = _context.Evaluations.Include(p => p.Points).Include(a => a.Activity)
.ThenInclude(m => m.MetaData).First(x => x.Id == evaluationid);
_context.Entry(evaluation.Activity).Reference(p => p.Person).Load();
_context.Entry(evaluation.Activity).Reference(l => l.Level).Load();
_context.Entry(evaluation.Activity).Collection(r => r.Relations).Load();
model.Evaluation = evaluation;
return View(model);
}
private RenderFormViewModel BuildViewModel(EvaluationForm form)
{
ApplicationUser user = _context.Users.Include(m => m.AssociationMembers).First(x => x.UserName == User.Identity.Name);
RenderFormViewModel model = new RenderFormViewModel { CustomerId = form.CustomerId, FormId = form.Id, FormVersion = form.FormVersion, FormTitle = form.Name, UserId = user.Id };
foreach (EvaluationFormField field in form.Fields.OrderBy(x => x.SortOrder))
{
if (string.IsNullOrEmpty(field.Group))
{
//normal field
RenderGroup group = new RenderGroup();
RenderQuestion newQuestion = new RenderQuestion { Text = field.Text, FieldId = field.Id };
newQuestion.Answers.AddRange(field.Answers.OrderBy(o => o.SortOrder).Select(x => new RenderAnswer { Id = x.Id, Text = x.DisplayText, Value = x.Points }));
group.Questions.Add(newQuestion);
model.Groups.Add(group);
}
else
{
//grouped field
RenderGroup group = model.Groups.FirstOrDefault(x => x.GroupId == field.Group);
if (group == null)
{
//group does not exist... create + add answers
group = new RenderGroup { GroupId = field.Group };
if (field.SameAnswersForAll)
{
var answerfield = form.Fields.Where(x => x.Group == field.Group && x.Answers.Any())
.OrderBy(o => o.SortOrder).FirstOrDefault();
if (answerfield != null)
{
//adding general answers
group.Answers.AddRange(answerfield.Answers.OrderBy(o => o.SortOrder).Select(x => new RenderAnswer { Id = x.Id, Text = x.DisplayText, Value = x.Points }));
}
}
model.Groups.Add(group);
}
//creating the question
RenderQuestion newQuestion = new RenderQuestion { FieldId = field.Id, Text = field.Text, AllowComment = field.AddComment };
//adding specific answers
if (!field.SameAnswersForAll && field.Answers.Any())
newQuestion.Answers.AddRange(field.Answers.OrderBy(o => o.SortOrder).Select(x => new RenderAnswer { Id = x.Id, Text = x.DisplayText }));
group.Questions.Add(newQuestion);
}
}
return model;
}
#region create
}
}
NOTE Updated the script section
This is only a partial answer that does not address any shortcomings other than the script.
I would take small steps to refactor but ultimately I would use the built in validation on your model but that requires more learning/discussion.
This may be something you can change to keep moving forward, the below snippets are what has worked for me in the past but there are tons of opinions so see if works or helps:
Controller
[Route("VerifyForm")]
public IActionResult VerifyForm()
{
var viewModel = new VerifyModel()
{
Store = "",
DateFrom = DateTime.Now,
};
return View(viewModel);
}
/// <summary>
/// Called by a form post
/// </summary>
[HttpPost("VerifyForm")]
public IActionResult VerifyForm(VerifyModel model)
{
if (!ModelState.IsValid)
{
// finding modelstate validation errors
var errors = ModelState.Values.SelectMany(v => v.Errors);
foreach (var err in errors)
{
_logger.LogError($"Model State err: {err.ErrorMessage}");
}
return View(model);
}
// do something with the model data
// . . .
// return back to the view - or another view - whatever you wish
return View(model);
}
View
<form asp-action="VerifyForm" asp-controller="Admin" method="post">
<!-- form fields here -->
<!-- this triggers the post, called in .js -->
<input type="submit" id="inputSave" style="display: none" />
</form>
<!-- my visible button bound to in .js -->
<button id="buttonSaveUser" class="btn btn-sm btn-primary" title="Click to save">
Save
</button>
Javascript
First, see my comments about the view and your use of the submit function, change your view and then given that you can just modify your script
Second, move your script below to this point I saw in your view, the script should not run at the top:
<script>
// initialize the buttons or other ui events
// for those who complain: Yes, there are other ways to do things but this is simple
$(function(){
// I'll assume this is the name of your new button
// bind to the button this way, get rid of onClick in your view
$('#buttonSaveUser').on('click', function ()
{
// this is my call to do some other validation, if not valid just exit
if (ValidateForm() === false) return;
// triggers the submit button which triggers the post
$('#inputSave').click();
});
});
function ValidateForm() {
var isFormValid = true;
$("#evaluateform input,select").each(function () {
var FieldId = "span_" + $(this).attr("id");
if ($.trim($(this).val()).length == 0 || $.trim($(this).val()) == 0) {
$(this).addClass("highlight");
//Show required message along with the field
if ($("#" + FieldId).length == 0) {
$("<span class='error' id='" + FieldId + "'>Required</span>").insertAfter(this);
}
//If you fill and again make the field empty in that case again show the message
if ($("#" + FieldId).css('display') == 'none') {
$("#" + FieldId).fadeIn(500);
}
//$(this).focus();
isFormValid = false;
}
else {
$(this).removeClass("highlight");
if ($("#" + FieldId).length > 0) {
// Hide the message with the fade out effect
$("#" + FieldId).fadeOut(1000);
}
}
});
return isFormValid;
}
</script>
don't use the submit to run client side script - it's meant to trigger the form POST - I would create a basic button that is bound client side
get rid of the onClick='' and bind in javascript
Hope this helps somewhat.

JSON data null in controller

I am working to send multiple email/SMS by selecting the checkbox. And When I am receiving in my javascript function it's getting with data. But when I pass it to action method record count shows but all data are null. Below is my code with screenshot here
Here it is my Model:
public class BulkEmailSendViewModel
{
public BulkEmailSendViewModel()
{
Candidates = new List<CandidateData>();
}
public List<CandidateData> Candidates { get; set; }
public string Body { get; set; }
public string Subject { get; set; }
}
public class CandidateData
{
public string Email { get; set; }
public string CandidateId { get; set; }
public string Phone { get; set; }
public string CandidateName { get; internal set; }
}
//Select all selected checkbox
$("#bulkAction").change(function () {
var ddlId = $("#bulkAction").val();//to get sms or email
var chk_arr = $('.checkCandidate:checkbox:checked');
var chklength = chk_arr.length;
var json = '';
$('.checkCandidate:checkbox:checked').each(function () {
if (this.checked) {
var Phone = $(this).attr("candidatePhone");
var CandidateId = $(this).attr("candidateId");
var Email = $(this).attr("candidatEmail");
var item = '{\"Phone\":\"' + Phone + '\","CandidateId\":\"' + CandidateId + '\",\"Email\":\"' + Email + '\",\"CandidateName\":\"\"},';
json += item;
}
});
json = "[" + json.substr(0, json.length - 1) + "]";
SendBulkEmail(json);
});
My Javascript:
function SendBulkEmail(jsonObj) {
alert(jsonObj);
if (jsonObj.length > 0) {
var send = "/Utility/Notifications/BulkEmail";
$(".modal-title").text("Send Email");
//var data = {
// Candidates: eval(jsonObj)
//};
$.get(send, { bulkEmailSendViewModel: eval(jsonObj) }, function (result) {
$("#C_modal_body").html("");
$("#C_modal_body").html(result);
});
}
else {
$.alert("Email not found for this candidate.");
// e.stopPropagation();
}
}
My Controller:
public PartialViewResult BulkEmail(List<CandidateData> bulkEmailSendViewModel)
{
BulkEmailSendViewModel bulkDetail = new BulkEmailSendViewModel();
return PartialView(bulkDetail);
}
Why my all values are null even I am getting in javascript function?
change your javascript codes to this:
$("#bulkAction").change(function () {
var ddlId = $("#bulkAction").val();//to get sms or email
var chk_arr = $('.checkCandidate:checkbox:checked');
var chklength = chk_arr.length;
var data = [];
$('.checkCandidate:checkbox:checked').each(function () {
if (this.checked) {
var Phone = $(this).attr("candidatePhone");
var CandidateId = $(this).attr("candidateId");
var Email = $(this).attr("candidatEmail");
var item = {Phone: Phone,
CandidateId: CandidateId,
Email : Email,
CandidateName : ""};
data.push(item);
}
});
SendBulkEmail(data);
});
and the SendBulkEmail to:
function SendBulkEmail(data) {
if (data.length > 0) {
var send = "/Utility/Notifications/BulkEmail";
$(".modal-title").text("Send Email");
//var data = {
// Candidates: eval(jsonObj)
//};
$.post(send, { bulkEmailSendViewModel: JSON.stringify(data) }, function (result) {
$("#C_modal_body").html("");
$("#C_modal_body").html(result);
});
}
else {
$.alert("Email not found for this candidate.");
// e.stopPropagation();
}
}
and finally:
[HttpPost]
public PartialViewResult BulkEmail(List<CandidateData> bulkEmailSendViewModel)
{
BulkEmailSendViewModel bulkDetail = new BulkEmailSendViewModel();
return PartialView(bulkDetail);
}
In your controller, I don't see any use of the bulkEmailSendViewModel input parameter.
Maybe, you could propagate the candidate list as follow:
public PartialViewResult BulkEmail(List<CandidateData> candidates)
{
BulkEmailSendViewModel bulkDetail=new BulkEmailSendViewModel();
bulkDetail.candidates = candidates;
return PartialView(bulkDetail);
}

How to build a javascript function as an object in C#?

I want to build an object in C# like this.
public JsonResult GetMyObject(){
var MyObject =
new
{
Myfunction = "function (params) {
var res = params[0].seriesName + ' ' + params[0].name;
res += '<br/> Start : ' + params[0].value[0] + ' Max : ' + params[0].value[3];
res += '<br/> End : ' + params[0].value[1] + ' Min : ' + params[0].value[2];
return res;
}",
Element1 = "Test Element",
Element2 = 123
};
return Json(MyObject);
}
But when I return the json object to javascript, the "Myfunction" element in MyObject is just a string, not a javascript function.
How can I build a javascript function as an object in C#?
If you want return object, better you can create a class, populate and send class as return item, it will send you JSON format.
public class MyFucntion
{
public string SeriesName { get; set; }
public string Start { get; set; }
public string End { get; set; }
public string Max { get; set; }
public string Min { get; set; }
}
public class MyObject {
public MyFucntion myFun { get; set; }
public string Element1 { get; set; }
public string Element2 { get; set; }
}
public JsonResult GetMyObject()
{
var fun = new MyFucntion
{
SeriesName =params[0].name,
Max = params[0].value[3],
Min = params[0].value[2],
Start =params[0].value[0],
End = params[0].value[1]
};
var obj = new MyObject {
myFun = fun,
Element1 ="ElE",
Element2 = "ELE2"
};
return JSON(obj);
}
If you are using asp.net website you can use web Mehtod and you need to change the code.
[System.Web.Services.WebMethod]
public static MyObject GetMyObject()
{
var fun = new MyFucntion
{
SeriesName =params[0].name,
Max = params[0].value[3],
Min = params[0].value[2],
Start =params[0].value[0],
End = params[0].value[1]
};
var obj = new MyObject {
myFun = fun,
Element1 ="ElE",
Element2 = "ELE2"
};
return obj;
}

Categories

Resources