Getting error in MVC Model regarding use of List(T) - c#

I am learning to build the application using one of the online tutorials regarding MVC. It requires to create a user db.
I am getting the following error while building the application. I have just copy-pasted the code from the tutorial. I googled few things, but I am not getting it. Please help to resolve and explain.
using System;
using System.Collections.Generic;
using System.Collections;
using System.EnterpriseServices;
namespace AdvancedMVCApplication.Models
{
public class Users
{
public List UserList = new List();
//action to get user details
public UserModels GetUser(int id)
{
UserModels usrMdl = null;
foreach (UserModels um in UserList)
if (um.Id == id)
usrMdl = um;
return usrMdl;
}
//action to create new user
public void CreateUser(UserModels userModel)
{
UserList.Add(userModel);
}
//action to udpate existing user
public void UpdateUser(UserModels userModel)
{
foreach (UserModels usrlst in UserList)
{
if (usrlst.Id == userModel.Id)
{
usrlst.Address = userModel.Address;
usrlst.DOB = userModel.DOB;
usrlst.Email = userModel.Email;
usrlst.FirstName = userModel.FirstName;
usrlst.LastName = userModel.LastName;
usrlst.Salary = userModel.Salary;
break;
}
}
}
//action to delete exising user
public void DeleteUser(UserModels userModel)
{
foreach (UserModels usrlst in UserList)
{
if (usrlst.Id == userModel.Id)
{
UserList.Remove(usrlst);
break;
}
}
}
}
}
Error: CS0305: Using the generic type 'List' requires 1 type arguments\Models\Users.cs Line:11
You can view the example here: https://www.tutorialspoint.com/mvc_framework/mvc_framework_advanced_example.htm

I was going to say "maybe the code blocks on tutorialspoint hide the necessary <xxx> after the List because it gets interpreted as an HTML tag".. but then I saw the next code block had actual html tags in just fine
To expand on the point Klaus made, it is possible to write classes in C# that are completed by the compiler rather than you. You specify some placeholder for the type of object the class deals with and then the compiler can use it to create an actual class in the background for you
class TenThings<T>{
private T[] _things = new T[10];
private T GetFirst(){
return _things[0];
}
}
T isn't any type in your program, or in the framework, for the purposes of this class/as written here but if you then say somewhere else:
var tt = new TenThings<string>();
Then the compiler can know "anywhere T is mentioned, in this case it needs to be a string" so it can knock together a class for you that is an array of ten strings and has a GetFirst method that returns a string. On the very next line you can have a TenThings<int> and you'll get another different type of class out that deals with ints. You created a template for the compiler to use to write code for you, and the benefit you get is that your GetFirst really does return a string in one case and an int in another. You could have just made a class like this:
class TenThings{
private object[] _things = new object[10];
private object GetFirst(){
return _things[0];
}
}
But then you have to cast everything that comes out - old classes like ArrayList worked this way, and it wasn't a great experience
List is a generic class like this new "templates" way; you really need to have another type of class in angle brackets after its name, such as List<UserModel> and it becomes a part of the type at the same time as dictating to the compiler how to create the template. Per the comment it seems that tutorials point forgot to put the relevant <UserModels> after the List
There are a few other things I take exception to in that tutorial, but talking specifically about this property; creating the List as a public field for one, calling the class UserModels when it seems to represent a single item (unwarranted plural / collections of items are typically recommended to have a name that ends with "Collection" - plurals are used for properties that are collections), I.e. it should be public List<UserModel> UserModels { get; set; } = new List<UserModel>();. I'll leave picking on it for not being a read only collection typed as something generic like IEnumerable<T> for another time :)

Related

Assigning Dynamic Variables from an Input Model C#

I am having some issues understanding how I can assign dynamic values from another class into other variables - I have tried using the correct namespaces, correct syntax and reading up on the documentation that the error provides - however no luck even when trying to implement examples shown. I have very little knowledge in regards to C# as I am mainly doing front end, however have to step up and start picking up some Back end oriented things at the company I work at
The current code I have is as follows:
BrazeConnectionInputs.cs
namespace Workflow.Connector.Braze.Models
{
public class BrazeConnectionInputs
{
public string Username { get; set; }
public string Password { get; set; }
}
}
CreateCampaign.cs
public class CreateCampaignRunner
{
private const string Username = BrazeConnectionInputs.Username; // BrazeConnectionInputs.Username errors
private const string Password = BrazeConnectionInputs.Password; // BrazeConnectionInputs.Username errors
}
You need to learn about objects vs classes. You should have an instance of the source class (BrazeConnectionInputs) that might be called something like model.
You can then explicitly assign across by creating a new instance of CreateCampaignRunner like var runner = new CreateCampaignRunner() and then assign the values in a number of ways:
Explicitly like runner.UserName = model.UserName
By using an explicit constructor var runner = new CreateCampaignRunner(model)
Object initializer syntax
Other ways are available
Highly recommend you do a basic C# course

Is there a way to derive a type argument from a string for passing into a generic method?

I typed this out in Notepad++ real quick so please forgive any typos/mistakes. If it's possible, I'd be getting rid of some repetitive work (i.e. a long case statement). Not a huge deal but I'm curious if it's possible and if so, how bad would it be to actually implement the code.
jsonFromWebpage = {
StatusUpdate: {
QueryType: "SomeClassName",
LocalCount: 5,
RemoteCount: 5
},
StatusUpdate: {
QueryType: "AnotherClass",
LocalCount: 29,
RemoteCount: 30
}
}
// Model
public class StatusUpdate
{
public string QueryType { get; set; }
public int LocalCount { get; set; }
public int RemoteCount { get; set; }
}
// Controller
public IActionResult GetStatusUpdate([FromBody] List<StatusUpdate> status)
{
_service.GetStatusUpdate(status);
return status
}
// Service
public List<Status> GetStatusUpdate(List<StatusUpdate> status)
{
foreach(var s in status)
{
var typeArgument = s.QueryType; // <--- Is there a way for this...
status.CurrentCount = GetTotalCount<typeArgument>(); // <--- to work here?
status.RemoteCount = thisworksfineforotherreasons(s.QueryType);
}
}
// Repo
public int GetTotalCount<T>() where T: class
{
var result = _db.GetCount<T>();
return result;
}
EDIT
First, thank you to everyone that has responded. Having read everything so far, I wanted to give a little more context. Here's a different take on the example:
// View
<div class="col-12">
<div class="api-types">History</div>
<div class="progress-bar">50 out of 50 copied</div>
</div>
<div class="col-12">
<div class="api-types">Users</div>
<div class="progress-bar">25 out of 32 copied</div>
</div>
// -- View javascript
var types = [];
$(".api-types").each(function (c, i) {
types.push({ ApiAndClassName: $(i).text() });
});
pushToController(JSON.stringify(types));
// Controller
public IActionResult GetSyncStatus(List<SyncStatusVM> status)
{
_service.GetSyncStatus(status);
return Json(status);
}
// Service
public List<SyncStatusVM> GetSyncStatus(List<SyncStatusVM> status)
{
foreach(var s in status)
{
// LocalCount
var magicTypeFigurator = s.ApiAndClassName
s.LocalCount = _repo.GetCount<magicTypeFigurator>(); <-- "this is a variable but should be a type..."
// Remote
var url = $"https://api.domain.com/{s.ApiAndClassName.ToLower()}"
s.RemoteCount = FetchCountFromApi(url);
}
return status;
}
// Repository
public long GetCount<T>()
{
var result = _orm.Count<T>();
return result;
}
// Models
public class SyncStatusVM
{
public string ApiAndClassName { get; set; }
public int LocalCount { get; set; }
public int RemoteCount { get; set; }
}
public class History
{
public long Id {get;set;}
public DateTime CreatedDate {get;set;}
public string Message {get;set;}
}
public class Users
{
public long Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
}
Using this code, I can just create a section in the view and a class for each type. The class is reused by the ORM and desearializing from the API. The most cumbersome point is having a case statement in the controller that calls the generic method with the correct type, based on the "ApiAndClassName". I could edit the ORM so it's string based instead of generic but I don't like that method for various reasons. I could turn the case statement into a collection in the controller or just move it to the service layer but what I have in place already works. I could also just refactor so the view builds from a collection but there are other data points where that wouldn't be the best option. Unless there's something I'm missing, the generic argument from string thing kinda makes sense. It's a fringe case... and kinda just curious if it can be done well enough.
Generally strong typsisation is your friend. Compile time type checks are a feature, not a enemy to be fought. Without them or with too agressive casting, we get the JavaScript and PHP examples from this comic.
For work with weakly typed langauges or WebServices, .NET has the ExpandoObject. The data can be stored in it, then later transfered into the proper type of instance. Also it looks like your case would fall into JSON deserialisation, wich is a well established code.
Generic is the wrong term. Generics are usually about the type still being known at compile time, so the compile time type checks still work. You are explicitly about the type not being known at compile time, only at runtime. This is very distinct from a generic. Dynamic Types are the proper term afaik. But to not mix it up with the type Dynamic (yes, naming here becomes really confusing).
Reflection is the droid you are looking for. For most purposes, the name of a class or field does not exist at runtime. It is primarily there for you and the compiler to communicate. Now Reflection is the exception. It is all about getting stuff (like instances or property/fields) based on a string representation of their name. The nessesary metadata is baked into the .NET Assemblies, as much as the COM support. But as I support strong typisation, I am not a friend of it.
switch/case statements can usually be replaced with a collection of some sort. Cases are really just a hardcoded way to check a collection of constants. You use the case identifier as the key and whatever else you need for the Value. You can totally use Functions as the value (thanks to delegates). Or the Type type, you then use for the instance creation.
But for your case it sounds like all of this is wrong. Bog standart Inheritance - Inheritance might be the real droid you are looking for. A JSON service would not usually give you different instance in a single collection, unless those instances are related in some way. "SomeClassName" and "AnotherClass" should have another ancestor. Or in fact, they should even be just one class - QueryType is simply a string field of said class.
Assuming that you have a way to map strings to Type objects, yes: you can use MethodInfo.MakeGenericMethod():
var totalCount = (int) (
GetType()
.GetMethod("GetTotalCount")
.MakeGenericMethod(MapStringToType(s.QueryType))
.Invoke(this, null)
);
This assumes the presence of a method Type MapStringToType(string) in the local scope.
One way to map types would be to use a Dictionary<string, Type> and fill it with the allowed types and their respective names that will be used in the JSON data to refer to them.

Getting the right class by attribute based on string value

public ActionResult AddComplianceForm(string TemplateName)
{
}
In this ASP.net MVC5 application there is a folder Templates that contains a bunch of different classes that all have different TemplateName attributes. The first part of this method needs to find the class that has a TemplateName matching the string passed in. I then need to create an instance of whatever template matched. I am very new to working with attributes in C# so help would be very appreciated. I mostly need to know how to access that folder of classes in the program to look into it.
What you are trying to do is called "Reflection" in C#.
Below is the link to another answer that shows how to get all the classes in a namespace (I'm assuming that the physical folder implies the use of a unique namespace for the classes contained in the folder.)
Link to StackOverflow answer
**Btw you should look up reflection performance and see if it makes sense in your case. You may want to use a factory pattern instead.
This will work:
public class HomeController : Controller
{
public ActionResult AddComplianceForm(string TemplateName)
{
Assembly assembly = Assembly.Load("Testy20161006"); //assembly name
Type t = assembly.GetType("Testy20161006.Templates." + TemplateName); //namespace + class name
Object obj = (Object)Activator.CreateInstance(t);
return View();
}
Don't just use reflection
The typical way someone would deal with this is with Reflection and run-time type discovery/binding. However, this is probably a poor starting point in this exact situation. The template name is passed in as an action argument, presumably through binding to a value in the request string, and you don't want c# code that will instantiate whatever class is passed in from the web!!! That would be a serious security issue known as an insecure direct object reference.
Create a list
To mitigate the risk, the proper approach is to check the argument against a whitelist. Well, if we have a white list already, we may as well associate each item in the list with a lambda expression that returns the object you want.
class MyController
{
static private readonly Dictionary<string,Func<BaseTemplate>> _templateList = new Dictionary<string,Func<BaseTemplate>>();
static MyController()
{
_templateList.Add("ATemplate", () => return new ATemplate());
_templateList.Add("SomeOtherTemplate", () => return new SomeOtherTemplate());
_templateList.Add("JustOneMore", () => return new JustOneMore());
}
public ActionResult AddComplianceForm(string TemplateName)
{
BaseTemplate template;
try
{
template = _templateList[TemplateName]();
}
catch (KeyNotFoundException exception)
{
RedirectToAction("MyController", "InvalidTemplateError");
}
DoSomethingWithTemplate(template);
}
}
Create the list using Reflection
But what if you have a crap ton of templates? You don't want to hard code all those dictionary entries, right?
Well, you could tag each of the templates with a custom attribute, e.g. [TemplateAttribute], and then populate the list this way:
foreach (Assembly b in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (Type t in b.GetTypes())
{
var a = Attribute.GetCustomAttribute(t, typeof(TemplateAttribute));
if (a != null)
{
var localType = t; //Avoid closure on loop variable
_templateList.Add(t.Name, () => Activator.CreateInstance(localType) as BaseTemplate);
}
}
}
This will automatically iterate through all the types that are loaded for your application and find the ones with the TemplateAttribute. Only those types will be allowed in the action argument.
Notes:
In these examples I assume all of your templates inherit from a BaseTemplate, but if they have no ancestor in common (not recommended) I guess you could just use object.
In these examples, I store the list and implement the code in the controller, but if you are going for well-structured code you should consider moving all that stuff into some sort of factory class and just pass the string in from the controller.

ASP.NET MVC Razor View built on Viewmodel of two objects. Architecture advice How to update a calculated field referencing both objects

I working in an ASP.NET MVC5 project and have a viewmodel class called PlacementStudentIndexData which has four collections of Ienumerables,
The viewmodel class is declared as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Placementv2.Models;
using IdentitySample.Models;
namespace Placementv2.ViewModels
{
public class PlacementStudentIndexData
{
public IEnumerable<ApplicationUser> UserChoice1 { get; set; }
public IEnumerable<ApplicationUser> UserChoice2 { get; set; }
public IEnumerable<ApplicationUser> UserChoice3 { get; set; }
public IEnumerable<Placement> Placement { get; set; }
public double distance { get; set; }
}
Note the ApplicationUser is uses the user objects on the objects in Identity2.0.
The Placements Controller has a Details Action to pass ViewModel data to a razor view built on this ViewModel which performs a matching exercise between the two objects and returns three matched collections of Users and an collection with a single instance of Placement type based on the int value passed to the Action to indicate which Placement object to return)
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var viewModel = new PlacementStudentIndexData();
viewModel.Placement = db.Placements.Where(p => p.PlacementID== id.Value);
viewModel.UserChoice1 = db.Users.Where(p => p.Choice1 == viewModel.Placement.FirstOrDefault().PlacementOrganisation.PlacementTypeID).Where(p => p.Placed == false);
viewModel.UserChoice2 = db.Users.Where(p => p.Choice2 == viewModel.Placement.FirstOrDefault().PlacementOrganisation.PlacementTypeID).Where(p => p.Placed == false);
viewModel.UserChoice3 = db.Users.Where(p => p.Choice3 == viewModel.Placement.FirstOrDefault().PlacementOrganisation.PlacementTypeID).Where(p => p.Placed == false);
return View(viewModel);
Elsewhere in my Placement controller I have the following method and am looking for advice on how to update this distance into the individual user instances as calculated against the current placement instance. The calculation should be based on passing geocoordinates which are already stored in the database for the User object and the PlacementOrganisation (which is associated to the Placement)
public double CalculateDistance(double startlat, double startlong, double endlat, double endlong)
{
[Google MAPS API calculation and JSON deserialisation code here]
return distancekms;
}
My difficulty is where in my code to perform these calculations and I'm looking for advice on how to update the distance attribute for the existing three UserChoice1,UserChoice2, UserChoice3 collections (As a side note, I know these are ienumerables, is it wrong to describe them as collections?)
If so could someone give me an example of how I would extend out my Details controller action to include a call to this CalculateDistance method so that the updated distance attribute for each User instance is part of the ViewModel passed to the Razor View.
Note- I've already tried include a foreach block in the controller method which called the CalculateDistance method along the following lines
foreach (var item in viewModel.UserChoice1)
{
viewModel.UserChoice1.First().distance = Calculatedistance(viewModel.Placement.First().PlacementOrganisation.Latitude, viewModel.Placement.First().PlacementOrganisation.Longtitude, viewModel.UserChoice1.First().Latitude, viewModel.UserChoice1.First().Longtitude);
}
However, it's throwing the following exception:
"There is already an open DataReader associated with this Command which must be closed first."
Please let me know if you can see a way to achieve what I'm trying to do here within the Details action of my Placement controller. Alternatively, should I be looking to call this CalculateDistance method from the view as I iterate through the User objects, or performing the calculation via Javascript in the View itself.
Thanks in advance for any help/advice you can offer on this.
The Link that #Dandy provided did contain the solution in one of the lower voted answers on that link.
The solution is to append .ToList() to the Ienumerables and that seems to close the DataReader properly.
This eventually got me past the issue where my foreach loop was throwing an error
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var viewModel = new PlacementStudentIndexData();
viewModel.Placement = db.Placements.Where(p => p.PlacementID == id.Value).ToList();
viewModel.User = db.Users.Where(p => p.Placed == false).OrderBy(p=>p.distance).ToList();
foreach (ApplicationUser user in viewModel.User)
{
user.distance = Calculatedistance(user.Latitude,user.Longtitude, viewModel.Placement.FirstOrDefault().PlacementOrganisation.Latitude, viewModel.Placement.FirstOrDefault().PlacementOrganisation.Longtitude);
}
return View(viewModel);
}

I can't get a MongoDB "find" query to work using C#

I am trying to make a frontend for a MongoDB database using C#.
So far I have managed to get the connection and the insert method to work.
But I'm stuck with the find method as I am new to C# and .net in general.
public void FindDocument(string query) {
BsonDocument QueryDoc = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>(query);
MongoCursor result = Collection.FindAs(QueryDoc);
The last line is giving me a really long error:
the type arguments for the method 'MongoDB.Driver.MongoCollection.FindAs<TDocument>'(MongoDB.Driver.IMongoQuery) can't be inferrred from usage. Try to specify the type arguments explicitly)
I'm completely lost here. If it is necessary, I can post the entire class here. Let me know. I'm using this driver by the way: CSharpDriver-1.10.0 from https://github.com/mongodb/mongo-csharp-driver/releases
FindAs expects you tell what type (class) you're expecting, so you'd have to call something like Collection.FindAs<MyClass>(query).
However, your code seems a little more complex than necessary. It's usually easier to work with your classes directly and use QueryBuilders to create the query (they can also be passed to other methods as IMongoQuery).
class MyClass {
public ObjectId Id { get; set; }
public ObjectId UserId { get; set; }
public string Description { get; set; }
// ...
}
var coll = mongoDb.GetCollection<MyClass>("MyClass");
var result = coll.Find(Query<MyClass>.EQ(p => p.UserId == someId));
// result is now a MongoCursor<MyClass>
Also, please note that a completely new, async-aware version of the C# driver, is already in beta (currently 2.0.0-beta4). The interface has changed completely, so if you're starting now, it's probably easier to (only) learn the new interface.

Categories

Resources