This is my viewtrainees.cshtml.cs file snippets that contain the array code:
public class viewTraineeModel : PageModel
{
public string[] traineeinfo { get; set; }
(...)
In my OnGet():
string[] traineeinfo = new string[Convert.ToInt32(countnum)];
int i = 0;
while (trainees.Read())
{
traineeinfo[i] = trainees["t3_win"].ToString();
i++;
}
So everything is set in my array fine, I even tested it within the .cs file. However, when I pass the array or think I pass the array to the view it ALWAYS gives me an internal error.
I have tried on my viewtrainees.cshtml file:
#Model.traineeinfo[0]
And I get NullReferenceException: Object reference not set to an instance of an object. Error.
The head element of my code looks like this.
#page
#model T3_Landing.Pages.viewTraineeModel
#{
ViewData["Title"] = "View Trainees";
string[] traineeinfo = Model.traineeinfo as string[];
}
I have tried it with and without re-initializing the string array as seen above. I really want this to work.
Just a note I can pass regular strings just fine using #Model.examplestring but never an array, list, or object.
It's hard to tell without the full context, but it looks like you're hiding the class member by declaring a local variable within OnGet():
string[] traineeinfo = new string[Convert.ToInt32(countnum)];
This creates a local variable named traineeinfo that hides the class property (if that's the case I would expect a compiler warning). Since the class property is not set, you get a null reference exception in your Razor page.
Try just
traineeinfo = new string[Convert.ToInt32(countnum)];
I would also recommend using camel case to make it easier to read:
public string[] TraineeInfo { get; set; }
....
TraineeInfo = new string[Convert.ToInt32(countnum)];
Here on constructor, I think you may initialize string array for prevent null value.
public class viewTraineeModel : PageModel
{
public string[] traineeinfo { get; set; }
...
public viewTraineeModel()
{
traineeinfo=new string[0];
}
Please drop a screen shot or code snippet of how you're passing the data to your view from your controller method end. That will determine if you have the data you want to work with in your view in the first place.
Related
I am eventually trying to create a nav menu that can auto matically populate itself with the sites pages. I need to get a list of all the endpoints and store them to a database to be accessed by the logic (this will just be .txt or .json for now).
In my original post here: https://stackoverflow.com/questions/74988601/how-can-i-can-get-a-list-of-razor-pages-in-a-razor-pages-app I was able to get a list of all endpoints with a constructor, but unable to access these variables from anywhere but that specific razor page view. Thanks to Md Farid Uddin Kiron.
I tried simply copying the list to a variable in another class ("endpointStringTest" in the "JSONTest" class):
public class IndexModel : PageModel
{
public readonly IEnumerable<EndpointDataSource> _endpointSources;
public IndexModel(IEnumerable<EndpointDataSource> endpointDataSources)
{
_endpointSources = endpointDataSources;
}
public IEnumerable<RouteEndpoint> EndpointSources { get; set; }
public void OnGet()
{
EndpointSources = _endpointSources
.SelectMany(es => es.Endpoints)
.OfType<RouteEndpoint>();
foreach(var endpointSource in EndpointSources)
{
Console.WriteLine(endpointSource);
Debug.WriteLine(endpointSource.ToString());
JSONTest.endpointStringTest.Add(endpointSource.DisplayName);
}
Console.WriteLine(JSONTest.endpointStringTest);
Debug.WriteLine(JSONTest.endpointStringTest);
}
}
But this results in a null reference. If i understand correctly, this is due to constructors being initialized and deleted before normal classes are initialized? is there a way to work around this?
I also tried turning the above constructor into a regular method, but the variables were always null. I don't fully understand where "endpointDataSources" is getting it's value. It's obviously something to do with being initialized within a constructor, as thats the only time it's not null.
By writing the endpoints to a text file (or theoretically any kind of database) i can simply pass the info via that text file.
Index model: Gets a list of all page paths and then writes them to a text document. Obviously in practice you would want to format this as .json, .xml or to a database etc..
public class IndexModel : PageModel
{
public readonly IEnumerable<EndpointDataSource> _endpointSources;
public IndexModel(IEnumerable<EndpointDataSource> endpointDataSources)
{
_endpointSources = endpointDataSources;
}
public IEnumerable<RouteEndpoint> EndpointSources { get; set; }
public void OnGet()
{
EndpointSources = _endpointSources
.SelectMany(es => es.Endpoints)
.OfType<RouteEndpoint>();
//string filePath = App.enviroment;
StreamWriter writer = new StreamWriter("pagesTest.txt");
foreach (var endpointSource in EndpointSources)
{
Console.WriteLine(endpointSource);
Debug.WriteLine(endpointSource.ToString());
writer.WriteLine(endpointSource.ToString());
}
writer.Close();
}
}
PageListGetter model: this copies the contents of the previously created document and stores them in a variable.
public class PageListsModel : PageModel
{
public string? pageList;
public void OnGet()
{
StreamReader reader = new StreamReader("pagesTest.txt");
pageList = reader.ReadToEnd();
reader.Close();
}
}
I have also tested this on an Azure published version of the site and it works fine. I was concerned the filepaths may not line up or may be inaccessible from a regular model.
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
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 :)
I want to save some variables for future reference so I declared a class Container.cs
public class Container
{
public static String verifierCode;
}
and then I have my HomeController.cs where I update the Container's variables values:
public class HomeController : Controller
{
public ActionResult ValidateTwitterAuth()
{
Container.verifierCode = Request.Query.ElementAt(2).Value;
//do some stuff
}
public String sendTweet(String NewTweet)
{
var userCreds = AuthFlow.CreateCredentialsFromVerifierCode(Container.verifierCode, Container.authorizationId);
var user = Tweetinvi.User.GetAuthenticatedUser(userCreds);
user.PublishTweet(NewTweet);
return "sent!";
}
}
It gets updated in the ValidateTwitterAuth with the specific values but when the sendTweet method is called the Container.verifierCode is null.
I obviously tried to debug it but if I add the variable to quickwatch i get that
error CS0103: The name 'Container' does not exist in current context
Also, both the class and the container are in the same namespace.
Any idea/tip why this is happening? I am just trying to declare a global variable which I can access from other classes/controllers.
I apologise if this may sound like a beginner question but I'm just starting to get my hands on asp.net
EDIT: From the answers, my way of handling with the problem was wrong. Therefore I installed the Microsoft.AspNetCore.Session NuGet Package and used it like this:
HttpContext.Session.SetString("verifierCode", Request.Query.ElementAt(2).Value);
HttpContext.Session.SetString("authorizationId", Request.Query.ElementAt(0).Value);
and now it works. Thank you all for the answers!
You can store this data into session instead of class.as per below example
public class HomeController : Controller
{
public ActionResult ValidateTwitterAuth()
{
Session["verifierCode"] = Request.Query.ElementAt(2).Value;
//do some stuff
}
public String sendTweet(String NewTweet)
{
var userCreds = AuthFlow.CreateCredentialsFromVerifierCode(Session["verifierCode"], Container.authorizationId);
var user = Tweetinvi.User.GetAuthenticatedUser(userCreds);
user.PublishTweet(NewTweet);
return "sent!";
}
}
i have just change only verify code
Hey all new to the MVC world so I'm sure I am not doing something correct here. I am trying to call a function from the model page from my view index page to populate some tooltips.
In my model:
public class tips
{
public List<string> allTips()
{
List<string> theTips = new List<string>();
theTips.Add("example 1");
theTips.Add("example 2");
return theTips;
}
private List<string> _tips;
public List<string> getTips { get { return _tips; } set { _tips = allTips(); } }
}
And in my view:
public ActionResult Index()
{
var blah = new tips().getTips;
ViewBag.pageTips = blah;
return getMainData();
}
And then I have this on the razor page:
#Html.Raw(ViewBag.pageTips[1])
Which should display example 2 on the page but instead it just displays null as the value for the toolTips.
Currently it has a value of null when it gets to the return for the pageTips in my view.
So what would I be doing incorrectly? I put some stops here and there and notice that it never calls the allTips() function so that's a good starting place as to what I need to do in order to do that.
I just figured that calling the .getTips would fire off the theTips function?
You seem to be confusing constructors with properties in your model, which is very strange. I suspect you want something like this instead:
public class TipsObj
{
// a property
public List<string> Tips { get; set; }
// a constructor
public TipsObj()
{
Tips = new List<string>();
Tips.Add("example 1");
Tips.Add("example 2");
}
}
The idea here is that the constructor is called by default when you create a new instance of the object, so your Tips property will automatically be populated right away just by creating an instance of this.
Then in your controller action you can simply do this:
var tips = new TipsObj();
ViewBag.pageTips = tips.Tips;
Which will create an instance of the TipsObj and set a ViewBag property to the Tips property of that instance. Which was initialized in the constructor of that object.
Note that none of this really has anything to do with MVC, this is just creating an object in C# and using a property on that object.
Note also that I changed some of the names here. In C# class names should begin with a capital letter. Also, you don't want to call everything "tips" (and you don't want to call anything "blah"). Using meaningful and intuitive names makes your code easier to understand, which will help you understand what you're writing.
You are misunderstanding the concept of setter and using it as an "initializer", a setter is meant to set the value, to change it in other word. if you want to initialize it do it in the constructor.
Here you are using two different Lists, I don't really know why.
A working code would be:
public class tips
{
public tips()
{
_tips = new List<string>();
_tips.Add("example 1");
_tips.Add("example 2");
}
private List<string> _tips;
public List<string> getTips { get { return _tips; } set { _tips = value; } }
}
Then in the controller:
ViewBag.pageTips = new tips().getTips;
Then call it this way in the view:
#Html.Raw(ViewBag.pageTips[1])
Change your model like the following:
public class Tips
{
private List<string> _tips {get; set;}
public Tips()
{
_tips = new List<string>();
_tips.Add("example 1");
_tips.Add("example 2");
}
public List<string> getTips()
{
return _tips;
}
}
Then use it :
ViewBag.pageTips = new Tips().getTips();
There are a few things wrong here, but I'll start with answering your question directly... the reason ViewBag.pageTips[1] is null is because you never initialize the _tips array in your model. The only code that would do that is in the getTips property's setter, which is never invoked. If you attach a debugger it'll be apparent :)
You could refactor this in a few ways, including changing the allTips() method to a constructor, and initializing your collection there.
I don't want to put an example of that directly though. You mentioned you were new to MVC, so I want to show you how this should really be done. One of the big benefits of MVC is Model Binding, so forget about ViewBag.
Try this instead:
The Model
using System.Collections.Generic;
namespace WebApplication1.Models
{
public class TipsModel
{
public List<string> Tips { get; }
public TipsModel()
{
Tips = new List<string> {"example 1", "example 2"};
}
}
}
The Controller
public ActionResult Index()
{
var model = new TipsModel();
return View(model);
}
The View
#model WebApplication1.Models.TipsModel
#{
ViewBag.Title = "Index";
}
#Model.Tips[1]