C# Razor - Display value from list based on key - c#

I'm trying to display some text from a list depending on the key:
<td>#x.OutcomeSummary</td>
<td>#Model.SummaryOutcomes.FirstOrDefault(c => c.Value == x.OutcomeSummary).Name</td>
<td>#Model.SummaryOutcomes.FirstOrDefault(x.OutcomeSummary).Name</td>
In this case x.OutcomeSummary is 7 and I would like for it to get the relevant text from SummaryOutcomes with a key of 7.
The second line gives me the following error: System.NullReferenceException: Object reference not set to an instance of an object.
And the third line gives me an error saying that the FirstOrDefault command has invalid arguments.
It imports the following model:
public class DogSummaryView
{
public IEnumerable<DogIncident> Incidents { get; set; }
public IEnumerable<Category> SummaryOutcomes { get; set; }
public IEnumerable<Category> DogBreeds { get; set; }
}
This is the category class:
public class Category
{
public string Value { get; set; }
public string Name { get; set; }
public bool InUse { get; set; }
}
And this is the controller:
public ActionResult Summary()
{
var vm = new DogSummaryView
{
Incidents = repository.GetAllRecords().OrderByDescending(x => x.DateRecieved),
SummaryOutcomes = repository.GetAllSummaryOutcomes()
};
return View("Summary", vm);
}
And finally here you can see that the list is populated and initialized:
Is there anyway of getting it so that instead of displaying 7, it displays the correct summary outcome?
Thanks
Thank you so so much to fourpastmidnight for his persistent help with this, and not only helping me to find a solution, but also helping me to understand just exactly where the problem lied. Here's an updated (working!) solution:
#foreach (var x in Model.Incidents)
{
var summaryOutput = "";
var firstOutcomeSummary = Model.SummaryOutcomes.FirstOrDefault(c => c.Value == x.OutcomeSummary);
if (firstOutcomeSummary != null) { summaryOutput = Model.SummaryOutcomes.FirstOrDefault(c => c.Value == x.OutcomeSummary).Name.ToString(); }
<tr>
<td>#Html.Raw(summaryOutput)</td>
</tr>
}

Ok, the problem is you're trying to compare a string to an int.
Change the second line as follows:
#Model.SummaryOutcomes.FirstOrDefault(c => c.Value == x.OutcomeSummary.ToString()).Name;
// You could also use '.Value'.
That should solve your problem.
UPDATE
Hmm, maybe x.OutcomeSummary.ToString() is resulting in the type name of the enumeration and not the integer value of the enumeration constant value.
Try updating the above line to the following:
#Model.SummaryOutcomes.FirstOrDefault(c => c.Value == ((int)x.OutcomeSummary).ToString()).Name;
UPDATE 2014-03-21
According to the OP's latest comment, try the following:
// If x.OutcomeSummary is the outcome summary name, then....
var firstOutcomeSummary = #Model.SummaryOutcomes.FirstOrDefault(c => c.Name == x.OutcomeSummary)
if (firstOutcomeSummary != null)
// Do something here.
// Else, if x.OutcomeSummary is the outcome summary value, e.g. "7", then...
var firstOutcomeSummary = #Model.SummaryOutcomes.FirstOrDefault(c => c.Value == x.OutcomeSummary)
if (firstOutcomeSummary != null)
// Do something here.

FirstOrDefault will do just that return the first element that matches the predicate or return default, i.e. null. Calling .Name on a null object will throw a NullReferenceException
In sum, the behavior you are describing will occur if there's no instance of Category in the enumeration SummaryOutcomes whose value is 7.

Related

Find specific value from list in c# MVC

I have list with items like this:
selCountry[0] = {IdCountry = 1, LongName = "Austria", CountryUrl = "austria"}
selCountry[1] = {IdCountry = 5, LongName = "Brasil", CountryUrl = "brasil"}
I know CountryUrl and I need to find IDcountry
I tried these ways:
int idCountry;
string country = "brasil";
idCountry = Convert.ToInt32(selCountry.FirstOrDefault(m => m.CountryUrl == country).IdCountry);
idCountry = selCountry.Find(x => x.CountryUrl == country).IdCountry;
idCountry = selCountry.SingleOrDefault(x => x.CountryUrl == country).IdCountry;
Every time I get error
Object reference not set to an instance of an object
If I debug it I can see something similar like this:
System.Linq.Enumerable.SingleOrDefault(...) returned null.
Where did I make a mistake?
PS: My question isn’t about, how can I manage problem with null, but, where is problem in my code, because in my example "brasil" exists in the list, so, how can I get IdCountry? If I use only only First instead FirstOrDefault I get System.InvalidOperationException: 'Sequence contains no matching element' So how is it possible, that there is not matching element?
Declaration of my list
List<CountriesListModel> selCountry = new List<CountriesListModel>();
selCountry = listOfCoutry.CountriesList(24);
My model:
public class CountriesListModel
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int IdCountry { get; set; }
[Required]
public string LongName { get; set; }
public string CountryUrl { get; set; }
}
My debug result:
https://www.dropbox.com/s/3m8a81ltxn6kiew/listproblem.jpg?dl=0
here is the solution:
selCountry.Where(w=>w.CountryUrl.Equals(country)).select(s=>s.IDcountry)
As you see above you need to use .select(s=>s.IDcountry) because the result of Single of Where is one item which looks like
{IDcountry = 1, LongName = "Austria", CountryUrl = "austria"}
and from that you need to select IDcountry attribute.
(You can use Single instead of Where if you are sure you will have the country always if not you need to check if we have result and it is not null then select)
System.Linq.Enumerable.SingleOrDefault(...) returned null.
to fixed null value
var ID = selCountry.Where(x => x.IDcountry == 1).Select(s=>s.LongName ).FirstOrDefault();
I thank all of you. I'm stupid idiot - only problem was with - declaration string country - brasil vs. brazil. Really thanx to #NineBery. You saved my night....

Pass linq query result to viewmodel

In my MVC web application, I have linq query that feth the record from database, I want to display that record on view using viewmodel. I have tried with following code.
[HttpGet]
public ActionResult CreatePDF()
{
RentalAgreementEntities db = new RentalAgreementEntities();
String strSession1 = "39726-10275-6027589725",strStatus = "Y",strUserType = "L";
var q = (from um in db.User_Master
join ut in db.UserType_Master on um.US_SerialNo.ToString() equals ut.UT_UserNo
join pu in db.PropertyUser_Master on ut.UT_SerialNo.ToString() equals pu.PU_UserNo
join pr in db.Property_Master on pu.PU_PropertyNo equals pr.PR_SerialNo.ToString()
where pr.PR_MakerID == strSession1
&& ut.UT_Status == strStatus
&& ut.UT_UserType == strUserType
select new
{
um.US_FirstName,
um.US_LastName
}
).AsEnumerable().Select(um => new User_Master {
US_FirstName = um.US_FirstName.ToString(),
US_LastName=um.US_LastName
}).ToList();
var myviewmodel=new viewmodelPDF()
{
lsusermaster=q.ToList();
}
return View("pdfgenerationvw",myviewmodel);
}
I also created viemodel to manage all model's for to display on a view (Here, Just one model access code).
public class viewmodelPDF
{
public List<User_Master> lsusermaster { get; set; }
}
My model class, for which I am going to fetch record from database.
public partial class User_Master
{
public string US_FirstName { get; set; }
public string US_LastName { get; set; }
public int US_SerialNo { get; set; }
}
//Other Models
Now my problem is that, In my action code , when I am trying to assign query result to the lsusermaster of viewmodel then it gives compiler error as belows.
I don't know, why this compile error is thrown, How can I assign query result to viemodel property?
Try this:
var myviewmodel=new viewmodelPDF()
{
lsusermaster=q.ToList()
};
When you are using an object initializer in C#, you can't use ; between the properties, you use it at the end of the initializer
So just remove the ; (or use a ,, as suggested), and move it to the end of the initializer block
var myviewmodel=new viewmodelPDF()
{
lsusermaster=q.ToList()
};
Using a , works even if there are no more properties... it "looks" bad, but it makes easier to add new properties should you ever need them... if the code is final, I'd not use it, but that's personal preference

Find a generic DbSet in a DbContext dynamically

I know this question has already been asked but I couldn't find an answer that satisfied me. What I am trying to do is to retrieve a particular DbSet<T> based on its type's name.
I have the following :
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyDllAssemblyName")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyCallingAssemblyName")]
class MyDbContext : DbContext {
public DbSet<ModelA> A { get; set; }
public DbSet<ModelB> B { get; set; }
public dynamic GetByName_SwitchTest(string name) {
switch (name) {
case "A": return A;
case "B": return B;
}
}
public dynamic GetByName_ReflectionTest(string fullname)
{
Type targetType = Type.GetType(fullname);
var model = GetType()
.GetRuntimeProperties()
.Where(o =>
o.PropertyType.IsGenericType &&
o.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) &&
o.PropertyType.GenericTypeArguments.Contains(targetType))
.FirstOrDefault();
if (null != model)
return model.GetValue(this);
return null;
}
}
I have no trouble getting the type itself whether it is via a simple switch or reflection. I need however to return the type as a dynamic since I do not know what DbSet type it will be.
Then somewhere else in the same assembly, I use it this way :
// MyDbContext MyDbContextInstance..
var model = MyDbContextInstance.GetByName_SwitchTest("A");
var record1 = model.FirstOrDefault(); // It crashes here with RunTimeBinderException
At this point model contains an instance of a InternalDbSet<ModelA> type. From there, any use I do with the model object I get a RunTimeBinderException :
'Microsoft.Data.Entity.Internal.InternalDbSet' does not contain a definition for 'FirstOrDefault'
Investigating on the web, I found a blog post explaining that (dixit his blog) :
the reason the call to FirstOrDefault() fails is that the type
information of model is not available at runtime. The reason it's not
available is because anonymous types are not public. When the method
is returning an instance of that anonymous type, it's returning a
System.Object which references an instance of an anonymous type - a
type whose info isn't available to the main program.
And then he points that a solution :
The solution is actually quite simple. All we have to do is open up
AssemplyInfo.cs of the ClassLibrary1 project and add the following
line to it: [assembly:InternalsVisibleTo("assembly-name")]
I did try this solution on my code but it doesn't work. For info I have an asp.net 5 solution with two assemblies running on dnx dotnet46. An app and a dll containing all my models and DbContext. All the concerned calls I do are located on the dll though.
Does this solution have any chance to work ?
Am I missing something ?
Any pointers would be greatly appreciated ?
Thanks in advance
[EDIT]
I have tried to return IQueryable<dynamic> rather than dynamic and I could do the basic query model.FirstOrDefault(); but above all I'd like to be able to filter on a field too :
var record = model.FirstOrDefault(item => item.MyProperty == true);
So how did I do it when I am not aware of <T> during compile time.
First need to get the type as DbContext.Set method returns a non-generic DbSet instance for access to entities of the given type in the context and the underlying store.
public virtual DbSet Set(Type entityType)
Note here argument is the type of entity for which a set should be returned.And set for the given entity type is the return value.
var type = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(t => t.Name == <Pass your table name>);
now once I have this type
if(type != null)
{
DbSet context = context.Set(type);
}
Or a one liner would be
DbSet mySet = context.Set(Type.GetType("<Your Entity Name>"));
*Disclaimer: This response doesn't give a stricto sensu answer to my question. It is rather a different approach to resolve my own problem. I am aware this is a specific example for a given situation that will not work for everyone. I am posting this approach in the hope it helps someone but will not mark it as the answer as I am still hoping for a real solution.
To start with, let's accept the fact that the only useful information we can get out of the current code is whether a record exists or not.. Any attempt of a dynamic queries after that would give the RuntimeBinderException.
Then let's continue with another fact; DbContext.Add(object) and DbContext.Update(object) are not template based so we can use them to save our models ( Instead of db.A.Add() or db.A.Update() )
In my own situation, no more is required to work out a procedure
Define models a little differently
To start with, I need a field that is retrievable across all my models which should obviously be a way to identify a unique record.
// IModel give me a reliable common field to all my models ( Fits my DB design maybe not yours though )
interface IModel { Guid Id { get; set; } }
// ModelA inherit IModel so that I always have access to an 'Id'
class ModelA : IModel {
public Guid Id { get; set; }
public int OtherField { get; set; }
}
// ModelB inherit IModel so that I always have access to an 'Id'
class ModelB : IModel {
public Guid Id { get; set; }
public string WhateverOtherField { get; set; }
}
Re-purpose the dynamic queries a bit to do something we know works
I haven't found a way to do smart query dynamically, so instead I know I can reliably identify a record and know if it exists or not.
class MyDbContext : DbContext {
public DbSet<ModelA> A { get; set; }
public DbSet<ModelB> B { get; set; }
// In my case, this method help me to know the next action I need to do
// The switch/case option is not pretty but might have better performance
// than Reflection. Anyhow, this is one's choice.
public bool HasRecord_SwitchTest(string name) {
switch (name) {
case "A": return A.AsNoTracking().Any(o => o.Id == id);
case "B": return B.AsNoTracking().Any(o => o.Id == id);
}
return false;
}
// In my case, this method help me to know the next action I need to do
public bool HasRecord_ReflectionTest(string fullname)
{
Type targetType = Type.GetType(fullname);
var model = GetType()
.GetRuntimeProperties()
.Where(o =>
o.PropertyType.IsGenericType &&
o.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) &&
o.PropertyType.GenericTypeArguments.Contains(targetType))
.FirstOrDefault();
if (null != model)
return (bool)model.GetValue(this).AsNoTracking().Any(o => o.Id == id);
return false;
}
// Update and save immediately - simplified for example
public async Task<bool> UpdateDynamic(object content)
{
EntityEntry entry = Update(content, GraphBehavior.SingleObject);
return 1 == await SaveChangesAsync(true);
}
// Insert and save immediately - simplified for example
public async Task<bool> InsertDynamic(object content)
{
EntityEntry entry = Add(content, GraphBehavior.SingleObject);
return 1 == await SaveChangesAsync(true);
}
}
A little bit of plumbing to give a sense to my situation
Next, what I needed to do with that dynamic queries was a way to replicate data from a server down to my client. ( I have omitted a big chunk of the architecture to simplify this example )
class ReplicationItem
{
public ReplicationAction Action { get; set; } // = Create, Update, Delete
public string ModelName { get; set; } // Model name
public Guid Id { get; set; } // Unique identified across whole platform
}
Connecting the bits.
Now, here's the routine that connects the bits
public async void ProcessReplicationItem(ReplicationItem replicationItem)
{
using (var db = new MyDbContext())
{
// Custom method that attempts to get remote value by Model Name and Id
// This is where I get the strongly typed object
var remoteRecord = await TryGetAsync(replicationItem.ModelName, replicationItem.Id);
bool hasRemoteRecord = remoteRecord.Content != null;
// Get to know if a local copy of this record exists.
bool hasLocalRecord = db.HasRecord_ReflectionTest(replicationItem.ModelName, replicationItem.Id);
// Ensure response is valid whether it is a successful get or error is meaningful ( ie. NotFound )
if (remoteRecord.Success || remoteRecord.ResponseCode == System.Net.HttpStatusCode.NotFound)
{
switch (replicationItem.Action)
{
case ReplicationAction.Create:
{
if (hasRemoteRecord)
{
if (hasLocalRecord)
await db.UpdateDynamic(remoteRecord.Content);
else
await db.InsertDynamic(remoteRecord.Content);
}
// else - Do nothing
break;
}
case ReplicationAction.Update:
[etc...]
}
}
}
}
// Get record from server and with 'response.Content.ReadAsAsync' type it
// already to the appropriately
public static async Task<Response> TryGetAsync(ReplicationItem item)
{
if (string.IsNullOrWhiteSpace(item.ModelName))
{
throw new ArgumentException("Missing a model name", nameof(item));
}
if (item.Id == Guid.Empty)
{
throw new ArgumentException("Missing a primary key", nameof(item));
}
// This black box, just extrapolate a uri based on model name and id
// typically "api/ModelA/{the-guid}"
string uri = GetPathFromMessage(item);
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:12345");
HttpResponseMessage response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
return new Response()
{
Content = await response.Content.ReadAsAsync(Type.GetType(item.ModelName)),
Success = true,
ResponseCode = response.StatusCode
};
}
else
{
return new Response()
{
Success = false,
ResponseCode = response.StatusCode
};
}
}
}
public class Response
{
public object Content { get; set; }
public bool Success { get; set; }
public HttpStatusCode ResponseCode { get; set; }
}
ps: I am still interested in a real answer, so please keep posting for other answer if you have a real one to share.
You could use this to get the DBSet for a specific type:
public object GetByType(DbContextcontext, Type type) {
var methode = _context.GetType().GetMethod("Set", types: Type.EmptyTypes);
if (methode == null) {
return null;
}
return methode.MakeGenericMethod(type).Invoke(_context, null);
}

MVC model properties returning default value

Something weird is happening and I am not able to understand why.. here's the scenario -
I have a model with few properties when I populate the model the properties in model does have values set (checked by putting breakpoints). It comes on the view also but it is not being shown on textbox. It is showing the default value (guessing by seeing the item textbox on the page as it has 0).
Below is my model -
public class PriceEnquiryModel
{
[DisplayName("Item")]
public int item { get; set; }
[DisplayName("Description")]
public string description { get; set; }
[DisplayName("UOP")]
public string uop { get; set; }
[DisplayName("UOS")]
public string uos { get; set; }
[DisplayName("Pack Description")]
public string pack_description { get; set; }
[DisplayName("Pack Size")]
public string PackSize { get; set; }
}
This is the controller;s code -
public ActionResult Search(PriceEnquiryModel price)
{
var priceEnquiryModel = new PriceEnquiryModel();
// Read parameter values from form.
int item = Convert.ToInt32(Request.Form["txtSearch"].ToString());
int maxrow = Convert.ToInt32(Request.Form["txtmaxrow"].ToString());
string priceType = !string.IsNullOrWhiteSpace(price.priceType) && price.priceType.ToUpper().Equals("STA") ? "N" : "Y";
// Get the price information
var operationResult = priceBal.SearchPriceEnquiry(0, item, price.price_scheme, priceType, maxrow);
var priceEnquiryDomList = (List<PriceEnquiryDom>)operationResult[0].Result;
// Check if we have something
if (priceEnquiryDomList != null && priceEnquiryDomList.Count > 0)
{
// Parse the model.
priceEnquiryModel = helper.ConvertDomToModel(priceEnquiryDomList[0]);
// Prepare the list.
priceEnquiryModel.PriceEnquiryModelList = new List<PriceEnquiryModel>();
foreach (var priceEnquiryDom in priceEnquiryDomList)
{
var priceEnquiryModelListItem = helper.ConvertDomToModel(priceEnquiryDom);
priceEnquiryModel.PriceEnquiryModelList.Add(priceEnquiryModelListItem);
}
Session["mainModel"] = priceEnquiryModel;
}
// Prepare product drop down list items if searched by product desc
if (TempData.Count > 0 && TempData["Products"] != null)
{
var products = TempData["Products"] as List<ProductSearchByDescModel>;
ViewBag.Products = products;
}
return View("Index", priceEnquiryModel);
}
This is the model on the View (while debugging) -
This is how I am rendering the model on the view -
This is the page after running -
Does anyone has any idea what is going on ? I have done the same thing on multiple pages and all run as expected.
Thanks in Advance.
Rohit
The issue is that your method has parameter PriceEnquiryModel price but then you return a new instance of PriceEnquiryModel (named priceEnquiryModel). The process of model binding includes binding your model and adding its values to ModelState (along with any validation errors).
When you return the view, the html helper methods use the values from ModelState (not the models values) so attempting to change the values (which I assume is what priceEnquiryModel = helper.ConvertDomToModel(priceEnquiryDomList[0]); is doing) is ignored by the helpers.
For an explanation of why this is the default behavior, refer the second part of this answer
One option to call ModelState.Clear() before setting new values for the properties of PriceEnquiryModel

Request values from query string

How could i extract House, Car, and Work value from this query string?
http://'mysite'/Result/Environments?House=1&Car=0&Work=1
Then assign values in LINQ statement below.
Action Method in Controller
public ActionResult Environments()
{
//int totalSmokers = repository.Results.Where(x=>x.House =
return View();
}
You should have your ActionResult take them as parameters, like so (I'm assuming bool, if they're int, change them to int).
public ActionResult Environments(bool House, bool Car, bool Work)
Then you can use them in your LINQ statement, something like:
int totalSmokers = repository.Results
.Where(x => x.House == House && x.Car == Car && x.Work == Work)
.Count();
Even cleaner though, you could create a model (and return this in your view like you asked in comments), something like:
public class SmokersModel
{
public bool House { get; set; }
public bool Car { get; set; }
public bool Work { get; set; }
public int TotalSmokers { get; set; }
}
Then that tidies up your action method, you can do:
public ActionResult Environment(SmokersModel Model)
{
Model.TotalSmokers = repository.Results
.Where(x => x.House == Model.House && x.Car == Model.Car && x.Work == Model.Work)
.Count();
return View(Model);
}
Then change your view's model type to be SmokersModel:
#model SmokersModel
You can add parameters to your Action to retrieve the values passed in the query string.
public ActionResult Environments(int House, int Car, int Work)
{
//int totalSmokers = repository.Results.Where(x=>x.House ==
return View();
}
You can also get it using Request["House"], Request["Car"] or Request["Work"] inside your function.
The following example writes the query ?House=1 to the console.
Uri baseUri = new Uri ("http://mysite.com/");
Uri myUri = new Uri (baseUri, "/Result/Environments?House=1&Car=0&Work=1");
Console.WriteLine(myUri.Query);
Hope this Helps!
You can access these through Request.QueryString. There a couple ways to do this. The simplest is probably Request.QueryString["House"], but keep in mind this will be a string. QueryString also has an AllKeys collection, so you can check that to see which values were actually provided.

Categories