I have need to import upwards of 35,000 Codes for a campaign from an excel spreadsheet. I have the following code below (which works in exactly the way i need it to) but when i run the process it can take over 20-30 mins to complete.
If there is anything that can be done to help speed up the process that would be greatly appreciated. I wouldn't call myself a advanced programmer and i know this could probably be done with advance coding techniques. If someone could point me in the right direction that would be greatly appreciated.
The models for the campaign and mastercode tables.
public class Campaign
{
public int CampaignId { get; set; }
public string Name { get; set; }
public virtual List<MasterCode> MasterCodes { get; set; }
}
public class MasterCode
{
public int MasterCodeId { get; set; }
public int CampaignId { get; set; }
public virtual Campaign Campaign { get; set; }
public string Code { get; set; }
public bool Used { get; set; }
public DateTime SubmittedOn { get; set; }
}
The following is the code in the view. The form fields are not model bound as this code is in a popup window on a view that is already model bound to another model.
#using (Html.BeginForm("UploadMasterCodes", "Campaigns", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.Hidden("CampaignId", Model.CampaignId)
<div class="form-group">
#Html.Label("Master Code File")
#Html.TextBox("File", null, new { type = "file", #class = "form-control" })
</div>
}
Controller Code
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UploadMasterCodes(CampaignMasterCodeUploadViewModel model)
{
if (ModelState.IsValid)
{
var result = CampaignMethods.uploadMasterCodes(model.File, model.CampaignId);
TempData["SuccessMessage"] = result;
return RedirectToAction("Details", new { id = model.CampaignId });
}
return RedirectToAction("Details", new { id = model.CampaignId });
}
And finally here is the code that performs the upload to the database. I am building a string that will track any errors that happen as i need to know of them all.
public static string uploadMasterCodes(HttpPostedFileBase file, int campaignId)
{
using (ApplicationDbContext _context = new ApplicationDbContext())
{
string response = string.Empty;
var campaign = _context.Campaigns.Find(campaignId);
if (campaign == null)
{
return String.Format("Campaign {0} not found", campaignId.ToString());
}
var submitDate = DateTime.Now;
int successCount = 0;
int errorCount = 0;
if ((file != null) && (file.ContentLength > 0) && !string.IsNullOrEmpty(file.FileName))
{
byte[] fileBytes = new byte[file.ContentLength];
var data = file.InputStream.Read(fileBytes, 0, Convert.ToInt32(file.ContentLength));
using (var package = new ExcelPackage(file.InputStream))
{
var currentSheet = package.Workbook.Worksheets;
var workSheet = currentSheet.First();
var noOfRow = workSheet.Dimension.End.Row;
for (int i = 1; i <= noOfRow; i++)
{
var masterCode = new MasterCode();
masterCode.Code = workSheet.Cells[i, 1].Value.ToString();
masterCode.CampaignId = campaignId;
masterCode.Campaign = campaign;
masterCode.SubmittedOn = submitDate;
// Check to make sure that the Code does not already exist.
if (!campaign.MasterCodes.Any(m => m.Code == masterCode.Code))
{
try
{
_context.MasterCodes.Add(masterCode);
_context.SaveChanges();
successCount++;
}
catch (Exception ex)
{
response += String.Format("Code: {0} failed with error: {1} <br />", masterCode.Code, ex.Message);
errorCount++;
}
}
else
{
response += String.Format("Code: {0} already exists <br />", masterCode.Code);
errorCount++;
}
}
response += string.Format("Number of codes:{0} / Success: {1} / Errors {2}", noOfRow.ToString(), successCount.ToString(), errorCount.ToString());
}
}
return response;
}
}
Whenever I need to read an Excel file I use this OLEDB provider:
Provider=Microsoft.ACE.OLEDB.12.0;Data Source={FilePath};Extended Properties='Excel 12.0 Xml;HDR=Yes;IMEX=1';
(More information on this topic can be found here and here)
Then you could do a bulk insert for the quickest insert.
See this answer how to do this in memory. In your case you'll first need to save the file somewhere on the server, process and report progress to the user.
On the suggestion of #grmbl, and lots of reading, I was able to solve the speed issue using SQLBulkCopy. I didn't use the OLEDB provider but instead copied the file to the server and created a datatable. Which i then used for the bulk copy. The following code got the runtime down to around 10 seconds for 335,000 records.
I have cut out all error checking code so its not a wall of code.
The controller code.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UploadMasterCodes(CampaignMasterCodeUploadViewModel model)
{
if (ModelState.IsValid)
{
var filename = Path.GetFileName(model.File.FileName);
var path = FileMethods.UploadFile(model.File, Server.MapPath("~/App_Data/Bsa4/"), filename);
var dt = CampaignMethods.ProcessMasterCodeCsvToDatatable(path, model.CampaignId);
TempData["SuccessMessage"] = CampaignMethods.ProcessMastercodeSqlBulkCopy(dt);
return RedirectToAction("Details", new { id = model.CampaignId });
}
TempData["ErrorMessage"] = "Master code upload form error. Please refresh the page and try again.";
return RedirectToAction("Details", new { id = model.CampaignId });
}
The processing code.
public static DataTable ProcessMasterCodeCsvToDatatable(string file, int campaignId)
{
using (ApplicationDbContext _context = new ApplicationDbContext()) {
var campaign = _context.Campaigns.Find(campaignId);
DataTable dt = new DataTable();
dt.Columns.Add("CampaignId");
dt.Columns.Add("Code");
dt.Columns.Add("Used");
dt.Columns.Add("SubmittedOn");
string line = null;
var submitDate = DateTime.Now;
using (StreamReader sr = File.OpenText(file))
{
while ((line = sr.ReadLine()) != null)
{
string[] data = line.Split(',');
if (data.Length > 0)
{
if (!string.IsNullOrEmpty(data[0]))
{
DataRow row = dt.NewRow();
row[0] = campaign.CampaignId;
row[1] = data[0];
row[2] = false;
row[3] = submitDate;
dt.Rows.Add(row);
}
}
}
}
return dt;
}
}
public static String ProcessMastercodeSqlBulkCopy(DataTable dt)
{
string Feedback = string.Empty;
using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
cn.Open();
using (SqlBulkCopy copy = new SqlBulkCopy(cn))
{
copy.ColumnMappings.Add(0, "CampaignId");
copy.ColumnMappings.Add(2, "Code");
copy.ColumnMappings.Add(3, "Used");
copy.ColumnMappings.Add(4, "SubmittedOn");
copy.DestinationTableName = "MasterCodes";
try
{
//Send it to the server
copy.WriteToServer(dt);
Feedback = "Master Code Upload completed successfully";
}
catch (Exception ex)
{
Feedback = ex.Message;
}
}
}
return Feedback;
}
Related
I want to test if mongo db can have a collection up to 50 000 000 000.
So I insert 10K elements every second using method:
public async Task InsertManyAsync(List<DBRoutLine> list)
{
await _collRouts.InsertManyAsync(list);
}
Data looks like this:
namespace DbLayer.Models
{
public class DBRoutLineMeta
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string id { get; set; }
public int counter { get; set; }
}
[BsonIgnoreExtraElements]
public class DBRoutLine
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string id { get; set; }
public DBRoutLineMeta meta { get; set; } = new DBRoutLineMeta();
public DateTime timestamp { get; set; } = DateTime.UtcNow;
public string some_data { get; set; } = DateTime.Now.ToString();
}
}
id members not required actually but I have them, just for testing.
So I've got exception like this:
"A bulk write operation resulted in one or more errors. WriteErrors: [ { Category : "DuplicateKey", Code : 11000, Message : "E11000 duplicate key error collection: TSTest.system.buckets.TSTable dup key: { _id: ObjectId('634e87301297fa65b7df9923') }" } ]."
after sometime. It can be also like this:
"time-series insert failed: TSTest.TSTable :: caused by :: Expected
And it will never recover from error even if I recreate connection to mongo server. Only application restart helps to insert records again.
Test code:
using DbLayer.Models;
using DbLayer.Services;
using MongoDB.Bson;
Console.WriteLine("Hello, World!");
var service = new RoutService();
try
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
var list = new List<DBRoutLine>();
for (int i = 0; i < 10000; i++)
{
DBRoutLine line = new DBRoutLine();
list.Add(line);
}
Task task = Task.Run(async () => {
int max_counter = await service.GetMaxCount();
bool recover = false;
while (!token.IsCancellationRequested)
{
try
{
if (!recover)
{
foreach (DBRoutLine line in list)
{
line.meta.counter = ++max_counter;
line.id = ObjectId.GenerateNewId().ToString();
line.meta.id = line.id;
}
}
var t1 = DateTime.Now;
await service.InsertManyAsync(list);
var t2 = DateTime.Now;
max_counter = await service.GetMaxCount();
var t3 = DateTime.Now;
Console
.WriteLine(
$"{max_counter}->Insert:{(int)(t2 - t1).TotalMilliseconds}, GetMax:{(int)(t3 - t2).TotalMilliseconds}");
recover = false;
}
catch(Exception ex)
{
recover = true;
await Task.Delay(3000);
Console.WriteLine(ex.Message.ToString());
service = new RoutService();
max_counter = await service.GetMaxCount();
}
}
}, token);
Console.WriteLine("Press any key to stop emulation\n");
Console.ReadKey();
tokenSource.Cancel();
Task.WaitAll(task);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Service code:
using DbLayer.Models;
using MongoDB.Bson;
using MongoDB.Driver;
namespace DbLayer.Services
{
public class RoutService:IDisposable
{
private readonly IMongoCollection<DBRoutLine> _collRouts;
private readonly MongoClient _mongoClient;
private readonly string CollName = "TSTable";
public RoutService(
)
{
var ConnectionString = "mongodb://mongoservice:27017";
_mongoClient = new MongoClient(
ConnectionString);
var mongoDatabase = _mongoClient.GetDatabase(
"TSTest");
var filter = new BsonDocument("name", CollName);
var options = new ListCollectionNamesOptions { Filter = filter };
if (!mongoDatabase.ListCollectionNames(options).Any())
{
var createOptions = new CreateCollectionOptions();
var timeField = nameof(DBRoutLine.timestamp);
var metaField = nameof(DBRoutLine.meta);
createOptions.TimeSeriesOptions =
new TimeSeriesOptions(timeField, metaField, TimeSeriesGranularity.Minutes);
mongoDatabase.CreateCollection(
CollName,
createOptions);
}
_collRouts =
mongoDatabase.GetCollection<DBRoutLine>(
CollName
);
CreateIndexes();
}
private void CreateIndexes()
{
{
IndexKeysDefinition<DBRoutLine> keys =
new IndexKeysDefinitionBuilder<DBRoutLine>()
.Descending(d => d.meta.counter);
var indexModel = new CreateIndexModel<DBRoutLine>(
keys, new CreateIndexOptions()
{ Name = "counter" }
);
_collRouts.Indexes.CreateOneAsync(indexModel);
}
////////////////////////////////////////////////
{
IndexKeysDefinition<DBRoutLine> keys =
new IndexKeysDefinitionBuilder<DBRoutLine>()
.Ascending(d => d.meta.id);
var indexModel = new CreateIndexModel<DBRoutLine>(
keys, new CreateIndexOptions()
{ Name = "id" }
);
_collRouts.Indexes.CreateOneAsync(indexModel);
}
}
public async Task InsertManyAsync(List<DBRoutLine> list)
{
await _collRouts.InsertManyAsync(list);
}
public async Task<int> GetMaxCount()
{
var last = await _collRouts
.Find(i=> i.meta.counter > 0)
.SortByDescending( i => i.meta.counter).FirstOrDefaultAsync();
if (last == null)
{
return 0;
}
return last.meta.counter;
}
public void Dispose()
{
}
}
}
project repository:
github.com/pruginkad/TestMongo
Ok, I found the bug. I changed timestamp only once when I created List of documents.
in this code:
foreach (DBRoutLine line in list)
{
line.meta.counter = ++max_counter;
line.id = ObjectId.GenerateNewId().ToString();
line.meta.id = line.id;
line.timestamp = DateTime.UtcNow;//missing line
}
I had to update timestamp, my mistake.
Anyway it's kind of strange that exception happen after every 17M documents and disappear after restart of mongo db
I would like to pass the model bind to devexpress gridview back to controller during callback but failed.
Models
public class UploadExcelError
{
public int rowNumber { get; set; }
public string errorMessage { get; set; }
}
public class UploadViewModel
{
public List<UploadExcelError> UploadExcelErrors { get; set; }
public UploadFile UploadFile { get; set; }
}
UploadErrorPartial.cshtml
#using ControlTower2.Models
#model ControlTower2.Models.UploadViewModel
#if (Model != null)
{
if (Model.UploadExcelErrors != null)
{
#Html.DevExpress().GridView(
settings =>
{
settings.Name = "gridViewExcelError";
settings.CallbackRouteValues = new { Controller = "PurchaseOrder", Action = "FilteringError", xyz = Model };
settings.SettingsBehavior.AllowSort = false;
settings.SettingsPager.Mode = GridViewPagerMode.ShowAllRecords;
settings.Columns.Add(column => { column.FieldName = "rowNumber"; column.Caption = "Excel Row#"; });
settings.Columns.Add(column => { column.FieldName = "errorMessage"; column.Caption = "Error Message"; });
settings.Settings.ShowHeaderFilterButton = true;
var headerFilterMode = GridHeaderFilterMode.List;
foreach (GridViewDataColumn column in settings.Columns)
column.SettingsHeaderFilter.Mode = headerFilterMode;
}
).Bind(Model.UploadExcelErrors).GetHtml()
}
}
Controller
public ActionResult FilteringError(UploadViewModel xyz)
{
return PartialView("UploadErrorPartial", xyz);
}
xyz is null in code above.
I also tried:
settings.CallbackRouteValues = new { Controller = "PurchaseOrder", Action = "FilteringError", xyz = Model.UploadExcelErrors };
public ActionResult FilteringError(List<UploadExcelError> xyz)
{
UploadViewModel uploadViewModel = new UploadViewModel();
uploadViewModel.UploadExcelErrors = xyz;
return PartialView("UploadErrorPartial", uploadViewModel);
}
xyz is not null but count is zero. But It has show 4 rows of data on UploadErrorPartial.cshtml
I tried ViewData too:
UPDATE - ViewData only transfers data from controller to view, that's why this won't work.
if (Model.UploadExcelErrors != null)
{
ViewData["xyz"] = Model;
#Html.DevExpress().GridView(
settings =>
{
settings.Name = "gridViewExcelError";
settings.CallbackRouteValues = new { Controller = "PurchaseOrder", Action = "FilteringError" };
settings.SettingsBehavior.AllowSort = false;
settings.SettingsPager.Mode = GridViewPagerMode.ShowAllRecords;
settings.Columns.Add(column => { column.FieldName = "rowNumber"; column.Caption = "Excel Row#"; });
settings.Columns.Add(column => { column.FieldName = "errorMessage"; column.Caption = "Error Message"; });
settings.Settings.ShowHeaderFilterButton = true;
var headerFilterMode = GridHeaderFilterMode.List;
foreach (GridViewDataColumn column in settings.Columns)
column.SettingsHeaderFilter.Mode = headerFilterMode;
}
).Bind(Model.UploadExcelErrors).GetHtml()
}
public ActionResult FilteringError()
{
UploadViewModel uploadViewModel = (UploadViewModel)ViewData["xyz"];
return PartialView("UploadErrorPartial", uploadViewModel);
}
uploadViewModel get null from (UploadViewModel)ViewData["xyz"].
I use session to store Model.UploadExcelErrors and it solves my problem.
I'm junior in MVC programming I have this code in controller:
[HttpPost]
public JsonResult SaveOrder(PonudiVM O)
{
bool status = false;
if (ModelState.IsValid)
{
try
{
using (leskaEntities dc = new leskaEntities())
{
ponudi ponuda1 = new ponudi { klID = O.klient, datum = O.datum, description = O.description };
foreach (var i in O.DetalnaPonuda)
{
ponuda1.ponudaDet.Add(i);
}
dc.ponudi.Add(ponuda1);
dc.SaveChanges();
//int last_id = db.ponudi.Max(item => item.pID);
status = true;
}
}
catch (BllException bllEx)
{
ModelState.AddModelError("", bllEx.Message);
}
catch (Exception ex)
{
//todo da se zapise vo LOG file
}
}
else
{
status = false;
}
return new JsonResult { Data = new { status = status } };
}
What I need to add in the code, to take new ID from master table then record ID to details table.
My data I send by Javascript and jQuery.
To get the last id simply do:
dc.ponudi.Add(ponuda1);
dc.SaveChanges();
int last_id = ponuda1.id;
If the detail table is ponudaDet, by the association, the ID should be already saved.
Background
I have master-detail gridview MVC 5 project using EF 6 Database First & DevExpress 15.2. The project structure given below (feel free to reproduce):
Model (ProjectModel.cs)
namespace Project.Models
{
// EF data context
public class ProjectContext : DbContext
{
public ProjectContext : base("DatabaseConnection")
{
}
public DbSet<Receipt> Receipts { get; set; }
public DbSet<SoldList> SoldLists { get; set; }
}
[Table("Receipt")]
public class Receipt
{
[Key]
public int ReceiptID { get; set; }
public String SessionID { get; set; }
public String MemberID { get; set; }
public String MemberName { get; set; }
public DateTime ReceiptDate { get; set; }
public String TransID { get; set; }
public decimal TotalPrice { get; set; }
public decimal RemainingCredit { get; set; }
public bool? UseRemainingCredit { get; set; }
}
[Table("SoldList")]
public class SoldList
{
[Key]
public int ItemID { get; set; }
public String SessionID { get; set; }
public String MemberID { get; set; }
public int TransID { get; set; }
public decimal TotalPrice{ get; set; }
public bool? UseRemainingCredit { get; set; }
}
}
Controller (MasterController.cs)
namespace Project.Controllers
{
public class MasterController : Controller
{
public ViewResult Transaction()
{
using (var DB = new ProjectContext())
{
var model = (from record in DB.Receipts select record).ToList();
return View(model);
}
}
// master grid partial view
public PartialViewResult PVTransaction()
{
using (var DB = new ProjectContext())
{
var model = (from record in DB.Receipts select record).ToList();
return PartialView("_MasterTrans", model);
}
}
// detail grid partial view
public PartialViewResult PVDetails(String sessionID, String memberID, String transID)
{
ViewData["TransID"] = transID;
// edit: adding forgotten IDisposable context declaration
using (var DB = new ProjectContext())
{
var model = (from list in DB.SoldLists where list.TransID == transID && list.MemberID == memberID && list.SessionID == sessionID select list).ToList();
return PartialView("_DetailTrans", model);
}
}
[HttpPost]
[ValidateInput(false)]
public PartialViewResult EditTrans(Receipt item)
{
using (var DB = new ProjectContext())
{
var model = (from record in DB.Receipts select record).ToList();
try
{
var match = DB.Receipts.FirstOrDefault(x => x.ReceiptID == item.ReceiptID);
if (match != null)
{
var sum = DB.SoldLists.Where(x => x.TransID == match.TransID).Select(x => x.TotalPrice).Sum();
var useRemaining = DB.SoldLists.Where(x => x.TransID == match.TransID).Select(x => x.UseRemainingCredit).FirstOrDefault();
if (item.TotalPrice - match.RemainingCredit != sum && (useRemaining == null || useRemaining == false))
{
// other unrelated code
}
else
{
match.SessionID = item.SessionID;
match.MemberID = item.MemberID;
// other data update definitions
this.UpdateModel(match);
DB.SaveChanges();
ViewBag.Success = "Selected data edited successfully.";
}
}
}
catch (Exception e)
{
ViewBag.Error = "Problem on editing with error message: \'" + e.Message + "\'";
}
return PartialView("_MasterTrans", model);
}
}
}
View (Transaction.cshtml)
#using Project.Models
<script type="text/javascript">
function onMasterInit(s, e) {
MasterGrid.PerformCallback();
}
function endMasterCallback(s, e) {
if (s.cpMasterMsg) {
alert(s.cpMasterMsg);
delete s.cpMasterMsg;
MasterGrid.Refresh();
}
else if (s.cpErrorMsg) {
alert(s.cpErrorMsg);
delete s.cpErrorMsg;
MasterGrid.Refresh();
}
}
</script>
<label class="description">Transaction List</label>
#using (Html.BeginForm())
{
Html.RenderAction("PVTransaction", "Master");
}
Partial View (_MasterTrans.cshtml)
#using Project.Models
#{
GridViewExtension grid = Html.DevExpress().GridView(settings =>
{
settings.Name = "MasterGrid";
settings.CallbackRouteValues = new { Controller = "Master", Action = "PVTransaction" };
settings.Width = Unit.Percentage(100);
settings.CommandColumn.ShowEditButton = true;
settings.CommandColumn.ShowUpdateButton = true;
settings.CommandColumn.ShowCancelButton = true;
settings.SettingsBehavior.AllowFocusedRow = true;
settings.SettingsBehavior.AllowSelectByRowClick = true;
settings.SettingsBehavior.ConfirmDelete = true;
settings.SettingsContextMenu.Enabled = true;
settings.SettingsContextMenu.EnableRowMenu = DefaultBoolean.True;
settings.SettingsContextMenu.EnableColumnMenu = DefaultBoolean.True;
settings.SettingsEditing.Mode = GridViewEditingMode.PopupEditForm;
settings.SettingsEditing.UpdateRowRouteValues = new { Controller = "Master", Action = "EditTrans" };
settings.SettingsText.ConfirmDelete = "Remove selected data?";
settings.SettingsText.ContextMenuExpandDetailRow = "Show Details";
settings.SettingsText.ContextMenuCollapseDetailRow = "Hide Details";
settings.ClientSideEvents.Init = "onMasterInit";
settings.ClientSideEvents.EndCallback = "endMasterCallback";
settings.CustomJSProperties = (s, e) =>
{
if (ViewBag.Success != null)
{
e.Properties["cpMasterMsg"] = ViewBag.Success.ToString();
e.Properties["cpErrorMsg"] = ViewBag.Error.ToString();
}
};
// begin detail gridview
settings.SettingsDetail.AllowOnlyOneMasterRowExpanded = false;
settings.SettingsDetail.ShowDetailButtons = true;
settings.SettingsDetail.ShowDetailRow = true;
settings.SetDetailRowTemplateContent(content =>
{
ViewContext.Writer.Write(#"<p style=""font-size:14px; text-decoration:underline"">Transaction Detail of " + DataBinder.Eval(content.DataItem, "MemberName") + " at " + String.Format("{0:yyyy/MMMM/dd}", DataBinder.Eval(content.DataItem, "ReceiptDate")) + ", Session ID: " + DataBinder.Eval(content.DataItem, "SessionID") + "</p>");
// this line throws FormatException on editing master grid while detail grid still open
Html.RenderAction("PVDetails", "Master", new { sessionID = DataBinder.Eval(content.DataItem, "SessionID"), memberID = DataBinder.Eval(content.DataItem, "MemberID"), transID = DataBinder.Eval(content.DataItem, "TransID")});
});
// end of detail gridview
settings.KeyFieldName = "ReceiptID";
settings.Columns.Add(column =>
{
column.FieldName = "ReceiptID";
column.Caption = "Receipt ID";
}
// other columns with similar construction
// including SessionID, MemberID, MemberName, ReceiptDate, TransID columns
}
}
#grid.Bind(Model).GetHtml()
Partial View (_DetailTrans.cshtml)
#using Project.Models
#{
GridViewExtension grid = Html.DevExpress().GridView(settings =>
{
settings.Name = "DetailGrid" + ViewData["TransID"]; // using transaction ID column from master grid to generate unique detail grid name
settings.CallbackRouteValues = new { Controller = "Master", Action = "PVDetails" };
settings.SettingsDetail.MasterGridName = "MasterGrid";
settings.KeyFieldName = "ItemID";
settings.Columns.Add(column =>
{
column.Name = "ItemID";
column.Caption = "Item ID";
});
// other columns with similar construction
}
}
#grid.Bind(Model).GetHtml()
Problem Statement
Master gridview provides editing transaction data and detail gridview shows item list by values from master grid. When user clicking Edit button, a popup edit window shows up providing editable data.
TransID property contains random 40-digit hexadecimal ensuring valid transactions.
All edit operations work fine if detail grid was hidden, but if a user trying to edit & update master grid content when a detail gridview still open (with collapse sign), FormatException was thrown (see details).
Despite view throwing exception, the edited data saved successfully but it will redirect to custom error page. I searched by keyword given inside additional information with no results.
Exception Details
An exception of type 'System.FormatException' occurred in System.Web.dll was caught.
HResult: -2146233033
Source: DevExpress.Web.v15.2
Additional information: Unexpected 'O' at 0
Stack Trace (simplified):
at DevExpress.Web.Internal.JsonReader.ReadCore()
at DevExpress.Web.Internal.JsonReader.Read(String jsonString)
at DevExpress.Web.Internal.HtmlConvertor.FromJSON(String jsonString)
at DevExpress.Web.Mvc.Internal.ExtensionValueProvidersFactory.GetValueProvider(ModelBindingContext bindingContext, String propertyName)
at DevExpress.Web.Mvc.DevExpressEditorsBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
at System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
at System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
at DevExpress.Web.Mvc.Internal.ContentControl`1.RenderInternal(HtmlTextWriter writer)
at DevExpress.Web.Mvc.Internal.ContentControl`1.Render(HtmlTextWriter writer)
at DevExpress.Web.Mvc.ExtensionBase.RenderControl(Control control)
at DevExpress.Web.Mvc.ExtensionBase.RenderCallbackResultControl()
at DevExpress.Web.Mvc.GridViewExtension.RenderCallbackResultControl()
at DevExpress.Web.Mvc.ExtensionBase.RenderCallbackResult()
Expected Result(s)
I want all editing operations running fine for every detail grid states.
Any help and suggestions welcome, thanks in advance.
I've been working on a website using ASP.NET MVC, in this website you can directly send an email to a specific email address. It's working properly, but the information being sent in the email (like Name, Email Address, ect.) don't have a database. So I tried adding a database for it, but somehow it's not working and I keep having some errors. I'm just new with this kind of stuff so I'm not sure if it's possible to send the email and at the same time save it to a database. I know there's something wrong with what I'm doing, so someone please help me. Thank you.
Here's my Controller for the sending of email:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(TalentInfo model, IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
RegisterRepository regRepo = new RegisterRepository();
if (regRepo.Register(model))
{
List<string> paths = new List<string>();
foreach (var file in files)
{
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
file.SaveAs(path);
paths.Add(path);
}
}
var message = new MailMessage();
foreach (var path in paths)
{
var fileInfo = new FileInfo(path);
var memoryStream = new MemoryStream();
using (var stream = fileInfo.OpenRead())
{
stream.CopyTo(memoryStream);
}
memoryStream.Position = 0;
string fileName = fileInfo.Name;
message.Attachments.Add(new Attachment(memoryStream, fileName));
}
//Rest of business logic here
string EncodedResponse = Request.Form["g-Recaptcha-Response"];
bool IsCaptchaValid = (ReCaptcha.Validate(EncodedResponse) == "True" ? true : false);
if (IsCaptchaValid)
{
var body = "<p><b>Email From:</b> {0} ({1})</p><p><b>Message:<b></p><p>{2}</p>";
message.To.Add(new MailAddress("***#gmail.com")); // replace with valid value
message.From = new MailAddress("***#ymailcom"); // replace with valid value
message.Subject = "YesDubai.org (REGISTRATION)";
message.Body = string.Format(body, model.Talent_Name, model.Talent_Email, model.Talent_SelfPromotion);
message.IsBodyHtml = true;
using (var smtp = new SmtpClient())
{
var credential = new NetworkCredential
{
UserName = "***#gmail.com", // replace with valid value
Password = "***" // replace with valid value
};
smtp.Credentials = credential;
smtp.Host = "smtp.gmail.com";
smtp.Port = 587;
smtp.EnableSsl = true;
smtp.SendCompleted += (s, e) =>
{
//delete attached files
foreach (var path in paths)
System.IO.File.Delete(path);
};
await smtp.SendMailAsync(message);
ViewBag.Message = "Your message has been sent!";
ModelState.Clear();
return View("Register");
}
}
else
{
TempData["recaptcha"] = "Please verify that you are not a robot!";
}
} return View(model);
}
}
And here's the Modal class:
public partial class TalentInfo
{
[Display(Name = "ID")]
public int TalentID { get; set; }
[Display(Name = "Talent's Name")]
public string Talent_Name { get; set; }
[Display(Name = "Email Address")]
public string Talent_Email { get; set; }
[Display(Name = "Self Promotion")]
public string Talent_SelfPromotion { get; set; }
}
And here's the Repository:
public class RegisterRepository
{
//SqlTransaction transaction = null;
private SqlConnection con;
//To Handle connection related activities
private void connection()
{
string constr = ConfigurationManager.ConnectionStrings["DefaultConnection"].ToString();
con = new SqlConnection(constr);
}
internal bool Register(TalentInfo model)
{
throw new NotImplementedException();
connection();
try
{
SqlCommand com = new SqlCommand("SP_INSERT_TALENT_INFO", con);
com.CommandType = CommandType.StoredProcedure;
com.Parameters.AddWithValue("#Talent_name", model.Talent_Name);
com.Parameters.AddWithValue("#Talent_email", model.Talent_Email);
com.Parameters.AddWithValue("#Talent_SelfPromotion", model.Talent_SelfPromotion);
con.Open();
int i = com.ExecuteNonQuery();
con.Close();
if (i >= 1)
{
return true;
}
else
{
return false;
}
}
catch
{
return Register(model);
}
finally
{
con.Close();
}
}
}
This is simply a compile error. You need to return a result in all paths of your code.
You have a missing return here
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(TalentInfo model, IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
//you have lots of code here....
}
else
{
//you need to return something here....because (ModelState.IsValid) might be false
}
}
There are 2 Errors in your code:
1) Return something when if (ModelState.IsValid) evaluates to false.
2) In the register method, remove this line :
throw new NotImplementedException();