C# MVC - Convert String to Variable - c#

How can I convert a string to be used as a variable? I have a List of strings that I want to be able to loop through and call data from my Model.
My code:
Controller:
List<string> reportContentsCharts = new List<string>();
//Pseudo Code
//If chart is selected added it to reportContents. So in the view instead of calling #Model.getChart1 from the view I can reference this reportContents.
//For Example:If chart1 and chart2 are selected
reportContentsCharts.Add("getChart1");
reportContentsCharts.Add("getChart2");
IndexViewModel viewModel = new IndexViewModel()
{
chart1 = makeChart1(DictionaryofData), //Returns an image and sends to IndexViewModel
chart2 = makeChart2(DictionaryofData),
chart3 = makeChart2(DictionaryofData),
chart4 = makeChart2(DictionaryofData),
chart5 = makeChart2(DictionaryofData),
chart6 = makeChart2(DictionaryofData),
reportContentsCharts = reportContentsCharts
}
private byte[] makeChart1(Dictionary<string, Double> DictionaryofData)
{
//code to construct chart and return as an image.
}
IndexViewModel:
public Byte[] chart1 { get; set; }
public Byte[] chart2 { get; set; }
public Byte[] chart3 { get; set; }
public Byte[] chart4 { get; set; }
public Byte[] chart5 { get; set; }
public Byte[] chart6 { get; set; }
//This code is repeated for all 6 charts
public string getChart1
{
get
{
string mimeType = "image/png";
string base64 = Convert.ToBase64String(chart1);
return string.Format("data: {0}; base64, {1}", mimeType, base64);
}
}
View:
<table>
for(int z = 0; z< Model.reportContentsCharts.Count / 2 ;z++) //At most 2 charts can be selected
{
<tr>
<td ="center">
<img src=#Model.reportContentsCharts[z]/>
</td>
<td ="center">
<img src=#Model.reportContentsCharts[z+1] />
</td>
</tr>
}
</table>
Under lying issue:
Currently when I run this code it returns me a broken image. I am thinking this might be a syntax issue? I have a handful of graphs that can be displayed on my webpage. Based on input from the user only a select few of the graphs will be displayed. The first thing I did was hard coded a position in the html for each graph and then use if() statements to determine whether to display the graph. The problem with this is that, based on the user input, the selected graphs can appear on separate lines. This creates bad alignment and spacing issues.
I understand that this might not be the best way to do this, but I felt like that it was the simplest solution.
Thanks for any suggestions or help.

It looks to me like the root of the problem is your poorly designed ViewModel. You need to normalize it:
private Dictionary<string, byte[]> Charts = new Dictionary<string, byte[]>();
public string GetChart(string name)
{
get
{
string mimeType = "image/png";
string base64 = Convert.ToBase64String(Charts[name]);
return string.Format("data: {0}; base64, {1}", mimeType, base64);
}
}
public string AddChart(string name, byte[] data)
{
Charts[name] = data;
}
Then you can write your controller something like this:
IndexViewModel viewModel = new IndexViewModel()
{
reportContentsCharts = reportContentsCharts
}
for (int i = 0; i < 6; i++)
{
viewModel.AddChart("chart" + i, makeChart("chart" + i, DictionaryOfData));
}
And finally, you can write your view like this:
<table>
for (int z = 0; z < Model.reportContentsCharts.Count; z += 2)
{
<tr>
for (int c = z; c < z + 2; c++)
{
<td align="center">
if (c < Model.reportContentsCharts.Count)
{
<img src="#Model.GetChart(Model.reportContentsCharts[c])"/>
}
</td>
}
</tr>
}
</table>

Related

Pass bool property value issue to make auto select checkbox using ASP.NET MVC and C#

I want to auto select two checkboxes of the files named "File1" and "File2" that have the job order type of 1 or 2 or 3 when the page is open. I use a property bool type in the Model to return true if the "File1" and "File2" are found in a For loop. But somehow, all the checkboxes of other files are automatically checked, it should be only the checkboxes for the "File1" and "File2." Here are my codes:
Web.Config
<appsettings>
<add key="JobOrderType" value="1,2,3"/>
</appsettings>
CustomerDocument.cs - my view model
public class CustomerDocument
{
public bool IncludeInEmail { get; set; }
public long DocumentId { get; set; }
public string DisplayName { get; set; }
public string DocumentPath { get; set; }
public bool IsAutoSelectFile { get; set; }
}
ShowJobTypeController.cs
[HttpGet]
public ActionResult ShowJobType() {
try
{
//Make auto select for File1 and File2 for some certain job order types
List<CustomerCustomers> customerDocuments;
var myQuery = dbTest2.JobOrders.FirstOrDefault(z => z.Id == JobOrderId);
var jobOrderTypeId = new List<int>();
var configJOTypeValues = ConfigurationManager.AppSettings["JobOrderType"].Split(',');
for (var i = 0; i < configJOTypeValues.Length; i++)
{
var IdValue = 0;
if (int.TryParse(configJOTypeValues[i], out IdValue))
jobOrderTypeId.Add(IdValue);
}
ViewBag.IsAutoSelectFileForJobOrder = false;
var vmCustomerDoc = new ViewModels.CustomerDocument();
var isDocSelected = false;
foreach (var doc in customerDocuments)
{
if (doc != null && jobOrderTypeId.Contains(myQuery.JobTypeId) && (doc.DocumentName.Contains("File1") || doc.DocumentName.Contains("File2")))
{
vmCustomerDoc.IsAutoSelectFile = true;
isDocSelected = vmPCustomerDoc.IsAutoSelectFile;
ViewBag.IsAutoSelectFileForJobOrder = isDocSelected;
}
else
{
vmCustomerDoc.IsAutoSelectFile = false;
ViewBag.IsAutoSelectFileForJobOrder = isDocSelected;
}
}
}
catch
{
//Leave it empty
}
return View();
}
ShowJobType.cshtml
#{
ViewBag.Title = "ViewJobType";
Layout = "~/Views/Shared/_Layout.cshtml";
}
var docs = ViewBag.CustomerDocuments as List<VM.CustomerDocument>; //Links to CustomerDocument.cs View Model
<table>
<tr>
<th>Check to Include in Email</th>
<th>Files</th>
</tr>
#foreach (var doc in docs)
{
<tr>
<td>
#{
var docValue = doc.DocumentId + (string.IsNullOrEmpty(doc.DocumentPath) ? "" : "/" + doc.DocumentPath);
}
<input type="checkbox" name="DocEmail" id="DocEmail" value="#docValue" #(ViewBag.IsAutoSelectGuideForJobOrder) ? "checked=\"checked\"" : "") />
</td>
</tr>
}
</table>
Assuming ViewBag.CustomerDocuments has the view models that have been updated to set their IsAutoSelectFile property, you can change your logic for displaying checks to check for that property value on each document and use it to add the check to the input field.
<input type="checkbox" name="DocEmail" id="DocEmail" value="#docValue" #(doc.IsAutoSelectFile) ? "checked" : "") />
Additionally, in your current logic in the back end, once isDocSelected is set to true, it will always be true. If you use the ViewModel's property instead of the view bag, you can remove it's usage from your logic anyways.

Using if statement in MVC view and controller

I am having a problem displaying different text based on the result I get from my controller.
Column command_status_codeis returning value between 0 to 12 from the table. However, I would like to display different text based on the values I get from the controller.
i.e if I get 0 I would like to display Verify and if I get 1 I would like to display Active and so on.
I am not sure if I add the check in the view or do the conversion in the controller itself.
Here is the relevant code:
View
#model List<Models.AuditLogs>
<table>
<tr>
<th>User</th>
<th>Command Status Code</th>
</tr>
#foreach (var AuditLogsDetail in Model)
{
<tr>
<td>#AuditLogsDetail.user_id</td>
<td>#AuditLogsDetail.command_status_code</td>
</tr>
}
</table>
Controller
public ActionResult AuditLogs() {
string connectionstring = "MY_CONNECTION_STRING";
string sql = "select * from table_name";
SqlConnection conn = new SqlConnection(connectionstring);
SqlCommand cmd = new SqlCommand(sql, conn);
var Details = new List < AuditLogs > (); {
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read()) {
var AuditLogsDetail = new AuditLogs {
user_id = rdr["user_id"].ToString(),
command_status_code = rdr["command_status_code"].ToString(),
};
Details.Add(AuditLogsDetail);
}
}
return View(Details);
}
Model
public class AuditLogs
{
public string user_id { get; set; }
public string command_status_code { get; set; }
}
}
I would leave the Controller for routing or controlling which view is called (which should be it's job, you should put as few presentation or application logic in the controller as possible).
Since this conversion is logic related to the model itself, I would put it in the Model class where it belongs and can be tested easily (if it becomes more complicated).
I would add a new property in the AuditLogsDetail model class which would return a string using a switch statement (since there are many possible values):
public class AuditLogsDetail
{
public int CommandStatusCode { get; set; }
public string CommandStatus
{
get
{
switch (CommandStatusCode)
{
case 0:
return "Verify";
case 1:
return "Active";
// and so on for the other 12 cases
default:
// you could throw an exception here or return a specific string like "unknown"
throw new Exception("Invalid Command Status Code");
}
}
}
}
In the Razor view you then simply have to call this property likewise:
<tr>
<td>#AuditLogsDetail.user_id</td>
<td>#AuditLogsDetail.CommandStatus</td>
</tr>
You could put a switch statement or if statement in the view but then you would clutter it. If you have several of these statements the view would be hard to read.
This sounds like a good candidate for an enum.
enum CommandStatus
{
def = 0,
success = 1,
A = 2,
B = 3,
...
}
public class AuditLogs
{
public string user_id { get; set; }
public CommandStatus command_status_code { get; set; }
}
Then when you fetch the value, just cast the int to the enum:
var AuditLogsDetail = new AuditLogs
{
user_id = rdr["user_id"].ToString(),
command_status_code = (CommandStatus)rdr["command_status_code"],
};
This doesn't provide the robustness of a switch, however.
in your view you can do something like this:
#model List<Models.AuditLogs>
<table>
<tr>
<th>User</th>
<th>Command Status Code</th>
</tr>
#foreach (var AuditLogsDetail in Model)
{
#if (#AuditLogsDetail.command_status_code == 0)
{
// what i need to do
}
#else if (#AuditLogsDetail.command_status_code == 1)
{
// what i need to do
}
<tr>
<td>#AuditLogsDetail.user_id</td>
<td>#AuditLogsDetail.command_status_code</td>
</tr>
}
</table>

ASP.NET MVC 5 Editor for 2-dimensional array

I have a model with two-dimensional array in it:
public class Matrix
{
public ValidInt[][] Data;
[Range(0, 8, ErrorMessage = "Введите ширину картины")]
public int Width { get; set; }
[Range(0, 8, ErrorMessage = "Введите ширину картины")]
public int Height { get; set; }
public Matrix(int w, int h)
{
Width = w;
Height = h;
Data = new ValidInt[w][];
for (int i = 0; i < w; i++)
this.Data[i] = new ValidInt[h];
}
public class ValidInt
{
[Range(0, 8, ErrorMessage = "Введите число, соответствующее цвету")]
public int Value { get; set; }
public ValidInt()
{
Value = 0;
}
}
}
Then I would like to have HTML.EditorFor to fill data in each block, so I write something like that:
<table>
#for (int column = 0; column < Model.Data.GetLength(1); column++)
{
<tr>
#for (int row = 0; row < Model.Data.GetLength(0); row++)
{
<td>#Html.EditorFor(x => Model.Data[column, row].Value); </td>
}
</tr>
}
</table>
But turns out you can't have EditorFor for two dimensional arrays. Any ideas on how to bypass that?
You cannot use two-dimensional array. However, you could use Jagged Array.
FYI: In order for ModelBinder to bind values to a model, it must have a parameterless constructor.
Model
public class Matrix
{
public int[][] Data { get; set; }
}
View
#using (Html.BeginForm())
{
<table>
#for (int column = 0; column < Model.Data.Length; column++)
{
<tr>
#for (int row = 0; row < Model.Data[column].Length; row++)
{
<td>#Html.EditorFor(x => Model.Data[column][row])</td>
}
</tr>
}
</table>
<button type="submit">Submit</button>
}
Controller
public IActionResult Index()
{
int w = 3, h = 2;
var matrix = new Matrix();
matrix.Data = new int[w][];
for (int i = 0; i < w; i++)
matrix.Data[i] = new int[h];
return View(matrix);
}
[HttpPost]
public IActionResult Index(Matrix matrix)
{
return View(matrix);
}
Result

Image is not displaying in the view ASP.NET MVC [duplicate]

This question already has answers here:
ASP.Net MVC: How to display a byte array image from model
(10 answers)
Closed 5 years ago.
I am trying to upload and retrieve image from SQL server database. I created model, Controller and view as below.
Viewmodel is very similiar to actual modal
CheckoutModel.cs
public class CheckOutViewModel
{
public int ID { get; set; }
public ApplicationUser CandidateId { get; set; }
[Required]
public byte[] Image { get; set; }
}
Also i created a controller to upload and display images with action methods namely index, create and retreive
Index method is used to display images , create method is used to upload and save image in database and retrieve method is used to query the image according to its id.
CheckOutController.cs
using Microsoft.AspNet.Identity;
using shanuMVCUserRoles.Repositories;
using shanuMVCUserRoles.ViewModels;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace shanuMVCUserRoles.Models
{
public class CheckOutController : Controller
{
private readonly ApplicationDbContext db;
public CheckOutController()
{
db = new ApplicationDbContext();
}
[Route("Index")]
[HttpGet]
public ActionResult Index()
{
var content = db.Checkouts.Select(s => new
{
s.ID,
s.CandidateId,
s.Image,
});
List<CheckOutViewModel> contentModel = content.Select(item => new CheckOutViewModel()
{
ID = item.ID,
CandidateId = item.CandidateId,
Image = item.Image,
}).ToList();
return View(contentModel);
}
public ActionResult RetrieveImage(int id)
{
byte[] cover = GetImageFromDataBase(id);
if (cover != null)
{
return File(cover, "image/jpg");
}
else
{
return null;
}
}
public byte[] GetImageFromDataBase(int Id)
{
var q = from temp in db.Checkouts where temp.ID == Id select temp.Image;
byte[] cover = q.First();
return cover;
}
// GET: CheckOut
[Authorize]
public ActionResult Create()
{
return View();
}
[Route("Create")]
[HttpPost]
public ActionResult Create(CheckOutViewModel model)
{
HttpPostedFileBase file = Request.Files["ImageData"];
CheckOutRepository service = new CheckOutRepository();
int i = service.UploadImageInDataBase(file, model);
if (i == 1)
{
return RedirectToAction("Index");
}
return View(model);
}
}
}
Then i created a repository folder to save images and fields in database and also a method for converted image to bytes.
CheckoutRepostiory.cs
public class CheckOutRepository
{
private readonly ApplicationDbContext db;
public CheckOutRepository()
{
db = new ApplicationDbContext();
}
public int UploadImageInDataBase(HttpPostedFileBase file, CheckOutViewModel contentViewModel)
{
contentViewModel.Image = ConvertToBytes(file);
var userId = HttpContext.Current.User.Identity.GetUserId();
var member = db.Users.Single(u => u.Id == userId);
var Content = new CheckOut
{
CandidateId = member,
Image = contentViewModel.Image
};
db.Checkouts.Add(Content);
int i = db.SaveChanges();
if (i == 1)
{
return 1;
}
else
{
return 0;
}
}
public byte[] ConvertToBytes(HttpPostedFileBase image)
{
byte[] imageBytes = null;
BinaryReader reader = new BinaryReader(image.InputStream);
imageBytes = reader.ReadBytes((int)image.ContentLength);
return imageBytes;
}
}
Also i created the index view and then i placed the image in image tag using the for each loop.
Index.cshtml
#foreach (var item in Model)
{
<tr>
<td>
<img src="/Content/RetrieveImage/#item.ID" alt="" height=100 width=200 />
</td>
</tr>
}
Something like this may work... if you have image bytes in your model object
#foreach (var item in Model)
{
<tr>
<td>
#{
var base64 = Convert.ToBase64String(item.Image);
var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
}
<img src="#imgSrc" alt="" height=100 width=200 />
</td>
</tr>
}
or
<img src="data:image;base64,#System.Convert.ToBase64String(item.Image)" width="200" height="100"/>
hope it helps
I have one alternative solution:
Alter your database table to set a field as varchar2
and store your image as string path on it:
Then after you same change, you can do in your MODEL as well as where it is required.
public class CheckOutViewModel
{
public int ID { get; set; }
public ApplicationUser CandidateId { get; set; }
[Required]
public string Image { get; set; }
}

Html table not populating from ViewModel

I am trying to populate an HTML table with data from a table in my database. The issue is simply that the HTML table is not getting populated with any data.
Here is the ViewModel:
public class TestViewModel
{
public string MatchedId { get; set; }
public string UnmatchedId { get; set; }
public string Auth { get; set; }
public DateTime CreditDate { get; set; }
public string CreditNumber { get; set; }
public decimal CreditAmount { get; set; }
public DateTime DeniedDate { get; set; }
public int DeniedReasonId { get; set; }
public string DeniedNotes { get; set; }
}
Controller Action:
[HttpPost]
public ActionResult UploadValidationTable(HttpPostedFileBase csvFile)
{
var inputFileDescription = new CsvFileDescription
{
SeparatorChar = ',',
FirstLineHasColumnNames = true
};
var cc = new CsvContext();
var filePath = uploadFile(csvFile.InputStream);
var model = cc.Read<Credit>(filePath, inputFileDescription);
try
{
var entity = new Entities();
//model here is the .csv, doesn't have anything to do with this issue
foreach (var item in model)
{
var tc = new TemporaryCsvUpload
{
Id = item.Id,
CreditAmount = item.CreditAmount,
CreditDate = item.CreditDate,
CreditNumber = item.CreditNumber,
DeniedDate = item.DeniedDate,
DeniedReasonId = item.DeniedReasonId,
DeniedNotes = item.DeniedNotes
};
entity.TemporaryCsvUploads.Add(tc);
}
entity.SaveChanges();
System.IO.File.Delete(filePath);
//This is where the database table is getting filled
entity.Database.ExecuteSqlCommand("Insert into CsvReport Select p.Id as MatchedId, case when p.Id is null then t.Id end as UnmatchedId, p.Auth,p.CreditDate, p.CreditNumber,p.CreditAmount, p.DeniedDate,p.DeniedReasonId, p.DeniedNotes from TemporaryCsvUpload t left join PermanentTable p on p.Id = t.Id;");
TempData["Success"] = "Updated Successfully";
}
catch (LINQtoCSVException)
{
TempData["Error"] = "Upload Error: Ensure you have the correct header fields and that the file is of .csv format.";
}
return View("Upload");
}
View:
#model IEnumerable<TestProject.TestViewModel>
#if (Model != null)
{
foreach (var item in Model.Where(x => x.IdMatched != null))
{
<tr>
<td>
#item.MatchedId
</td>
<td>
#item.Auth
</td>
<td>
#item.CreditDate
</td>
<td>
#item.CreditNumber
</td>
<td>
#item.CreditAmount
</td>
<td>
#item.DeniedDate
</td>
<td>
#item.DeniedReasonId
</td>
<td>
#item.DeniedNotes
</td>
</tr>
}
}
It's a little weird because I am populating the database with an SQL command. What am I missing here? Do I need to try and pass it through the controller action? Let me know if you need more information. Thanks!
Edit
I tried to pass the instance through, but I may still be doing it incorrectly:
var testModel = new TestViewModel();
return View("Upload", testModel);
Here is what its padding through:
public class TestViewModel
{
public IEnumerable<Test> Test { get; set; }
}
Made an answer so essentially the view doesn't know what to render you need to pass an actual filled model (in your case an IEnumerable to the view). This can be done using the method:
View("Upload", viewModelList);
Controller.View docs on MSDN
It looks like you are not adding any data to your view model.
If your view model is a collection of Test objects, you need to add some
Test objects to the collection.
var model = new TestViewModel()
{
Test = new List<Test>() { new Test(), new Test(), ... }
}
return View("Upload", model);

Categories

Resources