I'm trying to show multiple lists thru ViewModel. Currently started with one, but I'm getting the following runtime error:
An exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in System.Core.dll but was not handled in user code
Additional information: 'object' does not contain a definition for 'allLocationBasedPromotions
using System.Text;
using System.Threading.Tasks;
namespace FreeRolla.BaseObjects
{
class LocationBasedPromotion
{
public string Country { get; set; }
public string City { get; set; }
public string FlagIcon { get; set; }
public int HotelCount { get; set; }
public int StartingPrice { get; set; }
public string WeatherIcon { get; set; }
public string WeatherTemperature { get; set; }
public string CityImage { get; set; }
public List<LocationBasedPromotion> Promotions { get; set; }
}
}
using FreeRolla.BaseObjects;
namespace FreeRolla.BL
{
class HPLocationBasedPromotionProvider
{
public List<LocationBasedPromotion> GetAllPromotions()
{
return new List<LocationBasedPromotion>{
new LocationBasedPromotion{Country="UK", City="London", FlagIcon="", HotelCount=135, StartingPrice=350, CityImage="London.jpg", WeatherIcon="cloudy", WeatherTemperature="+18" },
new LocationBasedPromotion{Country="Spain", City="Barcelona", FlagIcon="", HotelCount=215, StartingPrice=230, CityImage="Barcelona.jpg", WeatherIcon="sunny", WeatherTemperature="+28" },
new LocationBasedPromotion{Country="Israel", City="Tel-Aviv", FlagIcon="", HotelCount=75, StartingPrice=280, CityImage="Tel-Aviv.jpg", WeatherIcon="sunny", WeatherTemperature="+32" }
};
}
}
}
using FreeRolla.BaseObjects;
using System.Web;
using System.Web.Mvc;
namespace FreeRolla.Models.ViewModels
{
class HomeView
{
public List<LocationBasedPromotion> allLocationBasedPromotions { get; set; }
}
}
using FreeRolla.BL;
using FreeRolla.Models.ViewModels;
namespace FreeRolla.Controllers
{
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
//return View();
HPLocationBasedPromotionProvider _BigPromotions = new HPLocationBasedPromotionProvider();
HomeView hv = new HomeView();
hv.allLocationBasedPromotions = _BigPromotions.GetAllPromotions();
return View(hv);
}
}
}
From the view - here the crash is occures:
#foreach (var item in Model.allLocationBasedPromotions)
{
Might be too obvious, but looks like your view file is missing this
#model FreeRolla.Models.ViewModels.HomeView
EDIT:
Your view class should have the following declaration:
namespace FreeRolla.Models.ViewModels
{
public class HomeView
{
public List<LocationBasedPromotion> allLocationBasedPromotions { get; set; }
}
}
The class LocationBasedPromotion should also be made public. Basically, as a tip, make every class public in your project, unless you have a good reason not too. As you gain more experience, you will encounter situations where you'll know when not to make a class public. But in your case, just make them public.
Related
All,
Edit: Firstly thanks for everyone's help. Secondly I'm new to Stack Overflow so apologises if I've added this edit incorrectly.
Following the commments and replies I've updated my class structure to:
services class:
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
namespace RTT_API
{
class services
{
public List<service> service = new List<service>();
public services()
{
}
}
}
Service class:
using System;
using System.Collections.Generic;
using System.Text;
namespace RTT_API
{
class service
{
public string atocCode{get; set;}
public service()
{
}
}
}
Unfortunately I'm still getting the same error. I think I still haven't quite matched my class structure to the JSON structure? Unfortunately I'm not sure where my mistake is. If it helps to highlight my mistake using a comparison then the following works:
Location class
using System;
using System.Collections.Generic;
using System.Text;
namespace RTT_API
{
class location
{
public string name { get; set; }
public string crs { get; set; }
public location()
{
}
}
}
Location deserilisation command and test output:
location locations = JsonSerializer.Deserialize<location>(channelResponse.RootElement.GetProperty("location").GetRawText());
MessageBox.Show(locations.crs);
Original question:
My JSON is as follows:
{
"location": {
"name": "Bournemouth",
"crs": "BMH",
"tiploc": "BOMO"
},
"filter": null,
"services": [
{
"locationDetail": {
"realtimeActivated": true,
"tiploc": "BOMO",
"crs": "BMH",
"description": "Bournemouth",
"wttBookedArrival": "011630",
"wttBookedDeparture": "011830",
"gbttBookedArrival": "0117",
"gbttBookedDeparture": "0118",
"origin": [
{
"tiploc": "WATRLMN",
"description": "London Waterloo",
"workingTime": "230500",
"publicTime": "2305"
}
],
"destination": [
{
"tiploc": "POOLE",
"description": "Poole",
"workingTime": "013000",
"publicTime": "0130"
}
],
"isCall": true,
"isPublicCall": true,
"realtimeArrival": "0114",
"realtimeArrivalActual": false,
"realtimeDeparture": "0118",
"realtimeDepartureActual": false,
"platform": "3",
"platformConfirmed": false,
"platformChanged": false,
"displayAs": "CALL"
},
"serviceUid": "W90091",
"runDate": "2013-06-11",
"trainIdentity": "1B77",
"runningIdentity": "1B77",
"atocCode": "SW",
"atocName": "South West Trains",
"serviceType": "train",
"isPassenger": true
}
]
}
My class structure is as follows:
servicelist class:
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
namespace RTT_API
{
class servicelist
{
public List<services> service = new List<services>();
public servicelist()
{
}
}
}
services class:
using System;
using System.Collections.Generic;
using System.Text;
namespace RTT_API
{
class services
{
public int serviceUid;
public services()
{
}
}
}
For deserialisation I have tried:
services servicelist = JsonSerializer.Deserialize<services>(channelResponse.RootElement.GetProperty("services").GetRawText());
and
servicelist servicelist = JsonSerializer.Deserialize<servicelist>(channelResponse.RootElement.GetProperty("services").GetRawText());;
In both cases I get 'System.Text.Json.JsonException'
I think there is a mismatch betwee the class structure and the JSON but I can't work what the problem is? It's the first time I've tried to desarialise an array.
Thanks
using System;
using System.Collections.Generic;
using System.Text;
namespace RTT_API
{
class location
{
public string name { get; set; }
public string crs { get; set; }
public location()
{
}
}
}
You can generate exact C# classes according to your JSON using tools for exactly that purpose. I used https://json2csharp.com/ , another is https://jsonutils.com/ - these are web services and don't require installation on computer, another option is generating classes through Visual Studio (with Web Essentials installed), there you would use Edit - Paste special - paste JSON as class.
Once you have the valid classes (I pasted generated classes below) you can deserialize entire Root object and then access any part of it, including services part:
// jsonInputText holds entire JSON string you posted
Root root = JsonSerializer.Deserialize<Root>(jsonInputText);
List<Service> serviceList = root.services;
Generated classes:
public class Location
{
public string name { get; set; }
public string crs { get; set; }
public string tiploc { get; set; }
}
public class Origin
{
public string tiploc { get; set; }
public string description { get; set; }
public string workingTime { get; set; }
public string publicTime { get; set; }
}
public class Destination
{
public string tiploc { get; set; }
public string description { get; set; }
public string workingTime { get; set; }
public string publicTime { get; set; }
}
public class LocationDetail
{
public bool realtimeActivated { get; set; }
public string tiploc { get; set; }
public string crs { get; set; }
public string description { get; set; }
public string wttBookedArrival { get; set; }
public string wttBookedDeparture { get; set; }
public string gbttBookedArrival { get; set; }
public string gbttBookedDeparture { get; set; }
public List<Origin> origin { get; set; }
public List<Destination> destination { get; set; }
public bool isCall { get; set; }
public bool isPublicCall { get; set; }
public string realtimeArrival { get; set; }
public bool realtimeArrivalActual { get; set; }
public string realtimeDeparture { get; set; }
public bool realtimeDepartureActual { get; set; }
public string platform { get; set; }
public bool platformConfirmed { get; set; }
public bool platformChanged { get; set; }
public string displayAs { get; set; }
}
public class Service
{
public LocationDetail locationDetail { get; set; }
public string serviceUid { get; set; }
public string runDate { get; set; }
public string trainIdentity { get; set; }
public string runningIdentity { get; set; }
public string atocCode { get; set; }
public string atocName { get; set; }
public string serviceType { get; set; }
public bool isPassenger { get; set; }
}
public class Root
{
public Location location { get; set; }
public object filter { get; set; }
public List<Service> services { get; set; }
}
If you need to deserialize only just a part of your json then you can use the JObject and JToken helper classes for that.
var json = File.ReadAllText("Sample.json");
JObject topLevelObject = JObject.Parse(json);
JToken servicesToken = topLevelObject["services"];
var services = servicesToken.ToObject<List<Service>>();
The topLevelObject contains the whole json in a semi-parsed format.
You can use the indexer operator to retrieve an object / array by using one of the top level keys.
On a JToken you can call the ToObject<T> to deserialize the data into a custom data class.
In order to be able to parse your json I had to adjust the services type because the W90091 as serviceUid can't be parsed as int. So here is my Service class definition:
public class Service
{
public string ServiceUid;
}
One thing to note here is that casing does not matter in this case so please use CamelCasing in your domain models as you would normally do in C#.
Thanks for everyone's help.
Firstly I had to make a few changes to the class names as they didn't match the JSON. I also had to change the syntax of two commands which I've detailed below:
I changed the definition of the list of objects from:
public List<services> service = new List<services>();
to:
public List<service> destination { get; set; };
and deserilisation command from:
services servicelist = JsonSerializer.Deserialize<services>(channelResponse.RootElement.GetProperty("services").GetRawText());
to
var servicelist = JsonSerializer.Deserialize<List<service>>(channelResponse.RootElement.GetProperty("services").GetRawText());
The change from services to var might not be the best solution. I think it's the first change, and matching the class names to the JSON, that fundamentally fixed the issue.
I have graphql.net implementation using conventions
I have my model defined as below.
public partial class Project
{
public Project()
{
ProjectGroup = new HashSet<ProjectGroup>();
ProjectUser = new HashSet<ProjectUser>();
Datasource = new HashSet<Datasource>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ProjectGroup> ProjectGroup { get; set; }
public virtual ICollection<ProjectUser> ProjectUser { get; set; }
public virtual ICollection<Datasource> Datasource { get; set; }
}
I am trying to update only name of above class.
using above class (which is basically kind of entity framework class, but that is irrelevant of this question)
So I have defined mutation as below.
public sealed class Mutation
{
public async Task<Project> SaveProject([Inject] IProjectRepository projectRepository, projectModels.Master.Project project)
{
return Mapper.Map<Project>(await projectRepository.SaveProject(project));
}
}
and I am calling this mutation as below.
axios
.post('https://localhost:44375/api/Graph', {
query: `mutation ($project: Project) {
saveProject(project: $project) {
name
}
}`,
variables: {
'project': { 'name' : data.label },
},
})
In response I am getting below error.
{"errors":[{"message":"Variable \"project\" cannot be non-input type \"Project\".","locations":[{"line":1,"column":11}],"extensions":{"code":"VALIDATION_ERROR"}}]}
what am I doing wrong?
From graphql.net convention's official repo, I found one example and there was one attribute used for input type. After use of that it is working.
https://github.com/graphql-dotnet/conventions/blob/master/samples/DataLoaderWithEFCore/DataLoaderWithEFCore/GraphApi/Schema/InputTypes/UpdateMovieTitleParams.cs
So it requires attribute something in a following way.
[InputType]
public class UpdateMovieTitleParams
{
public Guid Id { get; set; }
public string NewTitle { get; set; }
}
I'm connecting a MongoDB (Azure) with a MVC .NET C# project. The connection and object definition are working very good so far. My problem is when I try to add the method FIND() to return all the data in the object USER.
My Model:
using System;
using System.Collections.Generic;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;
using MongoDB.Driver.Builders;
namespace backendnet.Models
{
public class MongoCore
{
public class DB
{
static MongoClient Client = new MongoClient("mongodb://mydbconnect");
static public IMongoDatabase Database = Client.GetDatabase("mydb");
static public IMongoCollection<User> Users = Database.GetCollection<User>("users");
}
public class User
{
[BsonId]
public ObjectId Id { get; set; }
[BsonElement("email")]
public string Email { get; set; }
[BsonElement("password")]
public string Password { get; set; }
[BsonElement("name")]
public List<DimensionName> Name { get; set; }
[BsonElement("address")]
public List<DimensionAddress> Address { get; set; }
[BsonElement("permissions")]
public List<DimensionPermissions> Permissions { get; set; }
[BsonElement("status")]
public string Status { get; set; }
[BsonElement("created")]
public string Created { get; set; }
[BsonElement("updated")]
public string Updated { get; set; }
}
public class DimensionName
{
[BsonElement("first")]
public string First { get; set; }
[BsonElement("last")]
public string Last { get; set; }
}
public class DimensionAddress
{
[BsonElement("stree")]
public string Stree { get; set; }
[BsonElement("number")]
public string Number { get; set; }
[BsonElement("city")]
public string City { get; set; }
[BsonElement("state")]
public string State { get; set; }
[BsonElement("zipcode")]
public string Zipcode { get; set; }
[BsonElement("type")]
public string Type { get; set; }
}
public class DimensionPermissions
{
[BsonElement("list")]
public string List { get; set; }
[BsonElement("create")]
public string Create { get; set; }
[BsonElement("edit")]
public string Edit { get; set; }
[BsonElement("delete")]
public string Delete { get; set; }
}
}
}
My Controller:
using System;
using System.Collections.Generic;
using System.Web.Mvc;
using backendnet.Models;
using MongoDB.Bson;
namespace backendnet.Controllers
{
public class DashboardController : Controller
{
private string _viewFolder = "../Admin/Dashboard";
public ActionResult Index()
{
var results = new MongoCore.DB();
ViewData["ListPost"] = results.ToJson();
return View (_viewFolder);
}
}
}
My View partial:
<p>HERE: #ViewData["ListPost"]</p>
I get this:
HERE: { }
So I tried adding in the Model -> DB the method Find:
MongoCursor<User> cursor = Users.Find("Email" != "");
But always show an error:
Expression is always 'true' ["Email" != ""]
May anyone show me what I'm missing here?
I Don't See you calling MongoDB.Find()? I have pasted below my code I use for MongoDB C# driver in order to attain a record based on a key:value pair in my MongoDB database.
The Find or FindAsync method both require a BsonDocument Argument, which can be created using the Builders as seen below. Your filter can be empty, which would get all records since you are not filtering out anything.
Once you call the find method, you will be able to access the information using Lambda, or other query methods. You can see in my query i just need one record so i ask for FirstOrDefault. Hope this helps.
async Task<Document> IDal.GetRecordAsync(string key, string value)
{
try
{
if (Database == null) ((IDal)this).StartConnection();
var filter = Builders<BsonDocument>.Filter.Eq(key, value);
var cursor = await Collection.FindAsync(filter);
var bsondocument = cursor.FirstOrDefault();
return bsondocument == null ? null : _converter.ConvertBsonDocumentToDocument(bsondocument);
}
catch (Exception ex)
{
Console.WriteLine(ex);
return null;
}
}
public ActionResult GetUsers()
{
MongoServer objServer = MongoServer.Create("Server=localhost:27017");
MongoDatabase objDatabse = objServer.GetDatabase("DBName");
List UserDetails = objDatabse.GetCollection("Colletion_Name").FindAll().ToList();
return View(UserDetails);
}
I am trying to load data from an XML file into a c# class but am not getting data being loaded in Notifications. The rest of the class (not shown) is correctly populated so I am assuming that my class definition is incorrect. Can anyone shed any light on this?
public partial class ISTimetables
{
[XmlElement]
public List<ISNotification> Notifications { get; set; }
}
[Serializable()]
public partial class ISNotification
{
public ISNotification()
{
On = new List<ISProcessStep>();
Notify = new List<ISNotify>();
}
[XmlElement]
public List<ISProcessStep> On { get; set; }
[XmElement]
public List<ISNotify> Notify { get; set; }
}
[Serializable()]
public partial class ISNotify
{
public string Email { get; set; }
public string SimpleEmail { get; set; }
public string SMS { get; set; }
}
[Serializable()]
public enum ISProcessStep
{
[XmlEnum("Calculated")]
Calculated,
[XmlEnum("Reported")]
Reported,
[XmlEnum("Customer Approved")]
CustomerApproved,
[XmlEnum("Rejected")]
Rejected
}
The data I am trying to load is as follows:
<Notifications>
<Notification>
<On>Calculated</On>
<On>Reported</On>
<Notify SimpleEmail="me#company.com"/>
<Notify Email="you#company.com"/>
<Notify SMS="0123456789"/>
</Notification>
<Notification>
<On>Customer Approved</On>
<Notify Email="him#company.com"/>
</Notification>
</Notifications>
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
namespace ConsoleApplication21
{
class Program
{
const string FILEName = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlSerializer serializer = new XmlSerializer(typeof(ISTimetables));
XmlTextReader reader = new XmlTextReader(FILEName);
ISTimetables tables = (ISTimetables)serializer.Deserialize(reader);
}
}
[XmlRoot("Notifications")]
public partial class ISTimetables
{
[XmlElement("Notification")]
public List<ISNotification> Notifications { get; set; }
}
[XmlRoot("Notification")]
public partial class ISNotification
{
public ISNotification()
{
On = new List<ISProcessStep>();
Notify = new List<ISNotify>();
}
[XmlElement]
public List<ISProcessStep> On { get; set; }
[XmlElement]
public List<ISNotify> Notify { get; set; }
}
[Serializable()]
public partial class ISNotify
{
public string Email { get; set; }
public string SimpleEmail { get; set; }
public string SMS { get; set; }
}
[Serializable()]
public enum ISProcessStep
{
[XmlEnum("Calculated")]
Calculated,
[XmlEnum("Reported")]
Reported,
[XmlEnum("Customer Approved")]
CustomerApproved,
[XmlEnum("Rejected")]
Rejected
}
}
I want to show a calculated field in a view, so I tried to create a viewmodel like this:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace Facturacion.Models
{
public class Test
{
public int testId { get; set; }
[Required]
public decimal price { get; set; }
}
public class TestViewModel
{
[Key]
public int testId { get; set; }
public Test test { get; set; }
public decimal price { get; set; }
public decimal calculated { get; set; }
public TestViewModel(Test test)
{
Test = test;
calculated = Test.price * 2;
}
}
}
It gave me an error so I changed the constructor:
public TestViewModel(Test test)
{
var foo = test;
calculated = foo.price * 2;
}
But now when I build the project, it creates a table called "TestViewModels", so I can not reach the data in the Tests table.
I think a viewmodel shouldn't have an id, but if it does not the scaffolder won't generate the controllers.
What is the correct way to use a viewmodel to show a calculated field in a view?
I could solve it without using the viewmodel
namespace Facturacion.Models
{
public class Test
{
public int testId { get; set; }
[Required]
public decimal price { get; set; }
public decimal calculated
{
get
{
return (decimal)(price*2);
}
}
}
}
Notice the calculated field does not have a set method.