.Net Core - Method Create Error NullReferenceException - asp.net-mvc

There are already some questions about this problem, but none of them actually solved my problem.
I'm trying to create the Create method of the Student.cs entity, but when I access the create url, this error appears, I really do not know how to solve it.
AlumniController.cs
line error: 32 var teachers = await _contextProfessor.FindAllAsync ();
Image error
Code
AlunoController.cs
public class AlunosController : Controller
{
public readonly AlunosService _contextAluno;
public readonly ProfessorService _contextProfessor;
public readonly TurmasController _contextTurma;
public AlunosController(AlunosService contextAluno)
{
_contextAluno = contextAluno;
}
public async Task<IActionResult> Index()
{
var lista = await _contextAluno.FindAllAsync();
return View(lista);
}
//GET
public async Task<IActionResult> Create()
{
var professores = await _contextProfessor.FindAllAsync();
var turmas = await _contextTurma.FindAllAsync();
var viewModel = new AlunoViewModel {
Professores = professores,
Turmas = turmas
};
return View(viewModel);
}
}
Turma.cs
public class Turma
{
public int Id { get; set; }
public int Numero { get; set; }
public string Curso { get; set; }
public ICollection<Aluno> Alunos { get; set; } = new List<Aluno>();
public Turma()
{
}
public Turma(int id, int numero, string curso)
{
Id = id;
Numero = numero;
Curso = curso;
}
}
Professor.cs
public class Professor
{
public int Id { get; set; }
public string Nome { get; set; }
public string Email { get; set; }
public string Telefone { get; set; }
public ICollection<Aluno> Alunos { get; set; } = new List<Aluno>();
public Professor()
{
}
public Professor(int id, string nome, string email, string telefone)
{
Id = id;
Nome = nome;
Email = email;
Telefone = telefone;
}
}
How can I solve this?
Code Complete HERE.

_contextProfessor is null. You will need to set it in the constructor of AlunosController.
public AlunosController(AlunosService contextAluno, ProfessorService professorService)
{
_contextAluno = contextAluno;
_contextProfessor = processorService;
}

You obviously have not assigned objects to _contextProfessor and _contextTurma fields, so you will naturally get a NullReferenceException if you try to refer to their methods and properties. So, firstly, you need to inject ProfessorService and TurmasController into controller constructor.
But for injection to be successfull, you need to specify the dependecies in your Startup class ConfigureServices method, otherwise the dependecy won't be able to be resolved an InvaidOperationException will be thrown.

Because you forgot to include that service in the call in the constructor
public AlunosController(AlunosService contextAluno, ProfessorService contextProfessor)
//^^^^
{
_contextAluno = contextAluno;
_contextPrefessor = contextProfessor;
}
DI bit you a little. just because you add the one context to the constructor doesn't mean the others are instantiated for free.

Related

How Can I Use Custom Validation Attributes on Child Models of a DB Entity?

Summary:
I want a data annotation validator to reference another property in the same class (TitleAuthorAndPublishingConfiguration).
However, DB.SaveChanges() is not being called on this class directly. Rather it is being called on the parent of this class (WebsiteConfiguration).
Therefore validationContext.ObjectType is returning WebsiteConfiguration and I am unable to refer to properties of TitleAuthorAndPublishingConfiguration within the data annotation validator.
WebsiteConfiguration.cs
public class WebsiteConfiguration
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public TitleAuthorAndPublishingConfiguration TitleAuthorAndPublishing { get; set; }
public BookChaptersAndSectionsConfiguration BookChaptersAndSections { get; set; }
public SocialMediaLoginsConfiguration SocialMediaLogins { get; set; }
public TagGroupsConfiguration TagGroups { get; set; }
}
public class TitleAuthorAndPublishingConfiguration
{
public string BookTitle { get; set; }
public bool IsPublished { get; set; }
// how do I access a property of current model when calling DB.SaveChanges() on parent?
[RequiredIfOtherFieldIsEnabled("IsPublished")]
public string Publisher { get; set; }
}
// ... and other sub models...
ApplicationDbContext.cs
DbSet<WebsiteConfiguration> WebsiteConfiguration {get;set;}
Example Update Code
public void SeedWebsiteConfiguration()
{
var titleAuthorAndPublishingConfiguration = new TitleAuthorAndPublishingConfiguration()
{
// seed values
};
var bookChaptersAndSectionsConfiguration = new BookChaptersAndSectionsConfiguration()
{
// seed values
};
var socialMediaLoginConfiguration = new SocialMediaLoginsConfiguration()
{
// seed values
};
var tagGroupsConfiguration = new TagGroupsConfiguration()
{
// seed values
};
var websiteConfiguration = new WebsiteConfiguration()
{
TitleAuthorAndPublishing = titleAuthorAndPublishingConfiguration,
BookChaptersAndSections = bookChaptersAndSectionsConfiguration,
SocialMediaLogins = socialMediaLoginConfiguration,
TagGroups = tagGroupsConfiguration
};
DB.WebsiteConfiguration.Add(websiteConfiguration);
DB.SaveChanges();
}
Validator Code
public class RequiredIfOtherFieldIsEnabledAttribute : ValidationAttribute
{
private string _ifWhatIsEnabled { get; set; }
public RequiredIfOtherFieldIsEnabledAttribute(string IfWhatIsEnabled)
{
_ifWhatIsEnabled = IfWhatIsEnabled;
}
protected override ValidationResult IsValid(object currentPropertyValue, ValidationContext validationContext)
{
var isEnabledProperty = validationContext.ObjectType.GetProperty(_ifWhatIsEnabled);
if (isEnabledProperty == null)
{
return new ValidationResult(
string.Format("Unknown property: {0}", _ifWhatIsEnabled)
);
}
var isEnabledPropertyValue = (bool)isEnabledProperty.GetValue(validationContext.ObjectInstance, null);
if (isEnabledPropertyValue == true)
{
if (String.IsNullOrEmpty(currentPropertyValue.ToString()))
{
return new ValidationResult(String.Format("This field is required if {0} is enabled", isEnabledProperty));
}
}
return ValidationResult.Success;
}
}
Questions
Is there a way for me to access child model properties from validationContext?
Am I misguided in my approach? Is there a better way to store multiple models as part of a larger model in a single DB table?
I was hoping not to have multiple config tables and calls to the DB. (There are 4 child models in this example, but there may be 10+ in the next app.)
The setup above meets my needs in so many ways. But I don't want to give up the functionality of DataAnnotations on the sub models!
Bonus Question
I have come across a few posts like this one:
How can I tell the Data Annotations validator to also validate complex child properties?
But that is 4 years old, and I'm wondering if anything has changed since then.
Am I trying to do something that is basically impossible (or at least very difficult)?
Am I trying to do something that is basically impossible (or at least
very difficult)?
No, there is a very simple solution that integrates perfectly with the framework and technologies using DataAnnotations.
You can create a custom ValidationAttribute that is called by EF Validation and call Validator.TryValidateObject inside. This way, when CustomValidation.IsValid is called by EF you launch child complex object validation by hand and so on for the whole object graph. As a bonus, you can gather all errors thanks to CompositeValidationResult.
i.e.
using System;
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
public class Program
{
public static void Main() {
var person = new Person {
Address = new Address {
City = "SmallVille",
State = "TX",
Zip = new ZipCode()
},
Name = "Kent"
};
var context = new ValidationContext(person, null, null);
var results = new List<ValidationResult>();
Validator.TryValidateObject(person, context, results, true);
PrintResults(results, 0);
Console.ReadKey();
}
private static void PrintResults(IEnumerable<ValidationResult> results, Int32 indentationLevel) {
foreach (var validationResult in results) {
Console.WriteLine(validationResult.ErrorMessage);
Console.WriteLine();
if (validationResult is CompositeValidationResult) {
PrintResults(((CompositeValidationResult)validationResult).Results, indentationLevel + 1);
}
}
}
}
public class ValidateObjectAttribute: ValidationAttribute {
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
var results = new List<ValidationResult>();
var context = new ValidationContext(value, null, null);
Validator.TryValidateObject(value, context, results, true);
if (results.Count != 0) {
var compositeResults = new CompositeValidationResult(String.Format("Validation for {0} failed!", validationContext.DisplayName));
results.ForEach(compositeResults.AddResult);
return compositeResults;
}
return ValidationResult.Success;
}
}
public class CompositeValidationResult: ValidationResult {
private readonly List<ValidationResult> _results = new List<ValidationResult>();
public IEnumerable<ValidationResult> Results {
get {
return _results;
}
}
public CompositeValidationResult(string errorMessage) : base(errorMessage) {}
public CompositeValidationResult(string errorMessage, IEnumerable<string> memberNames) : base(errorMessage, memberNames) {}
protected CompositeValidationResult(ValidationResult validationResult) : base(validationResult) {}
public void AddResult(ValidationResult validationResult) {
_results.Add(validationResult);
}
}
public class Person {
[Required]
public String Name { get; set; }
[Required, ValidateObject]
public Address Address { get; set; }
}
public class Address {
[Required]
public String Street1 { get; set; }
public String Street2 { get; set; }
[Required]
public String City { get; set; }
[Required]
public String State { get; set; }
[Required, ValidateObject]
public ZipCode Zip { get; set; }
}
public class ZipCode {
[Required]
public String PrimaryCode { get; set; }
public String SubCode { get; set; }
}

Pass JsTreeView data from database

I have a list of virtual folder structure. I need to bind that list to JsTreeView. The List may contain something like the below.
List of Items
Dh
Dh\Sub
Dh\Sub\Another
Dh1
Dh1\Sub1
Dh1\Sub1\Another1
Dh1\Sub1\Another2
Desired Output
Dh
|______ Sub
|_____Another
Dh1
|______ Sub1
|_____ Another1
|_____ Another2
As, I have tried logic using recursion. But, did not succeed with it. Can anybody tell me how can i achieve this. Any help to the problem will be highly appreciated.
Thanks
I am using the following class to serialize DB data to JSON and load into JS Tree View
/// <summary>
/// Model which represents data for js tree view
/// </summary>
public class JsTreeViewNode
{
private int int_id;
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "text")]
public string Text { get; set; }
[JsonProperty(PropertyName = "children")]
public List<JsTreeViewNode> Children { get; set; }
[JsonProperty(PropertyName = "a_attr")]
public AnchorAttribute AAttributes { get; set; }
[JsonIgnore]
public int CurrentLevel { get; set; }
[JsonIgnore]
public int SortOrder { get; set; }
public JsTreeViewNode()
{
AAttributes = new AnchorAttribute();
}
public JsTreeViewNode(int id)
: this()
{
int_id = id;
this.Id = int_id.ToString();
AAttributes.Id = this.Id;
}
public int GetNodeId()
{
return int_id;
}
public JsTreeViewNode Clone()
{
var clone = (JsTreeViewNode)this.MemberwiseClone();
clone.Children = new List<JsTreeViewNode>();
clone.AAttributes = this.AAttributes.Clone();
return clone;
}
}
public class AnchorAttribute
{
[JsonProperty(PropertyName = "draggable")]
public string Draggable = "false";
[JsonProperty(PropertyName = "id")]
public string Id;
[JsonProperty(PropertyName = "class", NullValueHandling = NullValueHandling.Ignore)]
public string CssClassname;
public virtual AnchorAttribute Clone()
{
var clone = (AnchorAttribute)this.MemberwiseClone();
return clone;
}
}
Children property contains subnodes. Populating them depends on you app logic.
and later in controller
public virtual ContentResult LoadTreeData()
{
var treeData = Repository.GetTreeData();
return Content(JsonConvert.SerializeObject(treeData), "application/json");
}
Hope this helps

Delete statement not working properly?

My application is based upon code first entity framework.
I have model called module
public class Module
{
public long Id { get; set; }
public long ModuleTypeId { get; set; }
public ModuleType ModuleType { get; set; }
public string ModuleId { get; set; }
public PropertyConfiguration PropertyConfiguration { get; set; }
public DateTime DateEntered { get; set; }
}
And another Model class called OwnedModule
public class OwnedModule
{
public long Id { get; set; }
public PropertyConfiguration PropertyConfiguration { get; set; }
public long ModuleTypeId { get; set; }
public ModuleType ModuleType { get; set; }
public string ModuleId { get; set; }
public Guid ModuleOwnerId { get; set; }
public Module Module { get; set; }
public DateTime Start { get; set; }
public DateTime? End { get; set; }
}
The idea is that when u want to add new module into system u just add Module class, and OwnedModule is something that has a owner or is owned my someone.
So, basically OwnedModule contains Module and other properties. Here is the OwnedMOduleMap class
public class OwnedModuleMap : EntityTypeConfiguration<OwnedModule>
{
public OwnedModuleMap()
{
Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasKey(x => x.Id);
HasOptional(x => x.PropertyConfiguration).WithOptionalPrincipal().WillCascadeOnDelete();
HasRequired(x => x.ModuleType).WithMany().HasForeignKey(x => x.ModuleTypeId);
HasOptional(x => x.Module).WithOptionalDependent();
}
}
If I had to delete Module I would first have to delete it from OwnedModules table and then delete it from Modules table. IF it has a owner that is.
In my repository this is what I've done:
public void DeleteModule(long id)
{
var module = _dbSis.Modules.FirstOrDefault(t=>t.Id==id);
DeleteOwnedModule(module.ModuleId);
_dbSis.Entry(module).State = EntityState.Deleted;
_dbSis.SaveChanges();
}
public long GetOwnedModuleId(string moduleId)
{
var ownedModule= _dbSis.OwnedModules.FirstOrDefault(t => t.ModuleId == moduleId);
if (ownedModule != null)
{
return ownedModule.Id;
}
return 0;
}
public void DeleteOwnedModule(string moduleId)
{
var ownedModuleId = GetOwnedModuleId(moduleId);
var ownedModule = new OwnedModule
{
Id = ownedModuleId
};
_dbSis.Entry(ownedModule).State = EntityState.Deleted;
_dbSis.SaveChanges();
}
But right now my DeleteOwnedModule method is not working, I get error saying, why is this happening? What do i need to make my Delete statement work?
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
PS: if i were not to set the owner while adding a Module, then there is no problem while deleting it.
public void DeleteModule(long id)
{
var module = _dbSis.Modules.FirstOrDefault(t=>t.Id==id);
//DeleteOwnedModule(module.ModuleId);
_dbSis.Entry(module).State = EntityState.Deleted;
_dbSis.SaveChanges();
}
this works perfectly, if I were to delete it manually, then I can open database delete the module I want from OwnedModules table first then from Modules table. This works too but deleting from the method in repopsitory is not working
The problem is this method:
public void DeleteOwnedModule(string moduleId)
{
var ownedModuleId = GetOwnedModuleId(moduleId);
var ownedModule = new OwnedModule
{
Id = ownedModuleId
};
_dbSis.Entry(ownedModule).State = EntityState.Deleted;
_dbSis.SaveChanges();
}
You are creating a new OwnedModule with the id of an existing one. What you need to do is Find the existing module and set that instances state to Deleted (as you do for Module in the method DeleteModule)
public void DeleteOwnedModule(long id)
{
var ownedModule = _dbSis.OwnedModules.FirstOrDefault(t=>t.Id==id);
_dbSis.Entry(ownedModule).State = EntityState.Deleted;
_dbSis.SaveChanges();
}
Incidentally you have a lot of calls to SaveChanges(). Once you get all your code working you may want to consider reducing the number of calls to SaveChanges().

Object reference not set to an instance of an object.

i have 3 model:
1st one:
public class CreateFieldModel
{
public FieldModel fm { get; set; }
public CategoryModel cm { get; set; }
}
2nd one:
public class FieldModel
{
public string field_Name { get; set; }
public InputTypeModel itm { get; set; }
public string input1 { get; set; }
public string input2 { get; set; }
public string input3 { get; set; }
public string input4 { get; set; }
public List<InputTypeModel> inputs { get; set; }
}
3rd One:
public class InputTypeModel
{
public string inputTypeName { get; set; }
public string inputTypeDesc { get; set; }
}
2 methods:
1st One:
public List<InputTypeModel> getInputTypes()
{
var inptypes = edu.InputTypes;
List<InputTypeModel> listInputTypes = new List<InputTypeModel>();
foreach (var inpType in inptypes)
{
listInputTypes.Add(new InputTypeModel { inputTypeName = inpType.Input_Type_Name, inputTypeDesc = inpType.Input_Type_Description });
}
return listInputTypes;
}
when this method executes listInputTypes has three different values.. i check it by debugging.. so no roblem here. This methos is under the class FormManagement.. I am calling this method from the following action method:
[HttpGet]
public ActionResult createNewField(CreateFieldModel cfm, string fcode)
{
FormManagement ffm = new FormManagement();
cfm.fm.inputs = ffm.getInputTypes();
return View(cfm);
}
when cfm.fm.inputs = ffm.getInputTypes(); executes it is showing "Object reference not set to an instance of an object." message... I am quite beginner to mvc.. please help
Without knowing what you really want to achieve with cfm-parameter in your action, the only thing I can suggest is to check for null references and create new instances before you assign them:
[HttpGet]
public ActionResult createNewField(CreateFieldModel cfm, string fcode)
{
FormManagement ffm = new FormManagement();
if (cfm == null)
{
cfm = new CreateFieldModel();
}
if (cfm.fm == null)
{
cfm.fm = new FieldModel();
}
cfm.fm.inputs = ffm.getInputTypes();
return View(cfm);
}
Of course, this supposes that your not relying on incoming data through your route parameters. If you are, you need to check why the values are not getting passed in, but I'm guessing you don't need it as a parameter in the first place.

MVC 4 Web API NullException Error (Noobie)

I'm working on my first MVC 4 app, following the MVC First Web API Tutorial on Asp.net. I've left the names the same, but changed the model and controller code. Here's my model:
public class Product
{
public string SID { get; set; }
public string name { get; set; }
public string givenName { get; set; }
public string sn { get; set; }
public string mail { get; set; }
public string telephoneNumber { get; set; }
public string mobile { get; set; }
public string otherMobile { get; set; }
public string title { get; set; }
public string Manager { get; set; }
public DateTime whenChanged { get; set; }
}
public class ProductModel
{
public ProductModel()
{
ProductList = new List<Product>();
}
public IList<Product> ProductList { get; set; }
}
And here's my APIcontroller:
public class ProductsController : ApiController
{
ProductModel products = new ProductModel();
public IEnumerable<Product> GetAD()
{
DirectoryEntry domainRoot = new DirectoryEntry(LDAP_server);
DirectorySearcher searcher = new DirectorySearcher(searchStr);
SearchResultCollection results = searcher.FindAll();
foreach (SearchResult srchResult in results)
{
DirectoryEntry dirEntry = srchResult.GetDirectoryEntry();
if (dirEntry.Properties["givenName"].Value != null && dirEntry.Properties["sn"].Value != null && !dirEntry.Parent.Name.Contains("Terminated"))
{
products.ProductList.Add(new Product()
{
SID = dirEntry.Properties["sid"].Value.ToString(),
name = dirEntry.Properties["name"].Value.ToString(),
givenName = dirEntry.Properties["givenName"].Value.ToString(),
sn = dirEntry.Properties["sn"].Value.ToString(),
mail = dirEntry.Properties["mail"].Value.ToString(),
telephoneNumber = dirEntry.Properties["telephoneNumber"].Value.ToString(),
mobile = dirEntry.Properties["mobile"].Value.ToString(),
otherMobile = dirEntry.Properties["otherMobile"].Value.ToString(),
title = dirEntry.Properties["title"].Value.ToString(),
Manager = dirEntry.Properties["Manager"].Value.ToString(),
whenChanged = Convert.ToDateTime(dirEntry.Properties["whenChanged"].Value.ToString()),
});
}
}
return products.ProductList;
}
}
I'm getting the NullException on 'products.ProductList.Add(new Product()', am I missing something simple? Please forgive my coding, as I'm just trying to get this up and running, thanks.
the problem mostly likely is dealing with dirEntry, not Web API itself. rather than introduce LDAP into this, just create a bunch of dummy products to return.
FYI... there is also a memory leak issue with the use of LDAP objects. They need to be properly disposed of, both along the happy path and if an exception is thrown.
I'm an idiot. 'sid' is not the correct property name from AD, it is 'objectSid', thus always returning a null. I knew it was something simple.

Resources