NullReferenceException when nothing is null? - c#

I am testing (integration) my repository layer and I keep getting a null reference error from EF. My concern is, There is nothing in the object null when I run the debugger. In fact there is nothing in the entire method that is null. All of the properties are set up properly in Automapper and I am using real (not mocked) values for everything. They are all there and use the real version of the code.
Test:
[Test]
public void Clone_ShouldCloneUser()
{
using (var scope = new TransactionScope())
{
//arrange
var request = Builder<CloneUserRequest>.CreateNew()
.With(x => x.KeyToClone = 29)
.With(x => x.User = Builder<User>.CreateNew().With(y => y.Key = 0)
.Build())
.Build();
//act
_sut.Clone(request);
//assert
Assert.DoesNotThrow(() => _sut.Clone(request));
}
}
Method:
public void Clone(CloneUserRequest request)
{
var usersGroupsToBeCloned = _context.WebUserGroups.Where(x => x.UserKey == request.KeyToClone).ToList();
var webUser = _mappingService.Map(request.User, new WebUser());
webUser.WebUserGroups = usersGroupsToBeCloned;
//On this line I receive a NullReferenceException, but nothing is null
_context.WebUsers.Add(webUser);
_context.SaveChanges();
}
Stack Trace:
System.NullReferenceException : Object reference not set to an instance of an object.
at System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.MarkForeignKeyPropertiesModified()
at System.Data.Entity.Core.Objects.DataClasses.EntityReference.AddToNavigationPropertyIfCompatible(RelatedEnd otherRelatedEnd)
at System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.IncludeEntity(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)
at System.Data.Entity.Core.Objects.DataClasses.EntityCollection`1.Include(Boolean addRelationshipAsUnchanged, Boolean doAttach)
at System.Data.Entity.Core.Objects.DataClasses.RelationshipManager.AddRelatedEntitiesToObjectStateManager(Boolean doAttach)
at System.Data.Entity.Core.Objects.ObjectContext.AddObject(String entitySetName, Object entity)
at System.Data.Entity.Internal.Linq.InternalSet`1.<>c__DisplayClassd.<Add>b__c()
at System.Data.Entity.Internal.Linq.InternalSet`1.ActOnSet(Action action, EntityState newState, Object entity, String methodName)
at System.Data.Entity.Internal.Linq.InternalSet`1.Add(Object entity)
at System.Data.Entity.DbSet`1.Add(TEntity entity)
at Repositories.UserRepository.Clone(CloneUserRequest request) in UserRepository.cs: line 39
at Repositories.UserRepositoryIntegrationTests.Clone_ShouldCloneUser() in UserRepositoryIntegrationTests.cs: line 50
Is there something obvious that I am missing or a bug in EF perhaps?

I figured out what was wrong. Our DB structure is terrible and there is actually a circular reference between WebUserGroup (it has a child WebUser) and WebUser(It has collection of WebUserGroups). So when I got all of the UserGroups to clone for the user, It had a reference to the user that I was initially cloning. Somehow EF decided to send me a nullReferenceException. When I changed the WebUser Property on the Groups to the new one it works great. Now its time to talk to my DBA's about updating this...

Related

IMemoryCache.GetOrCreateAsync returns null

I have a lot of NullReferenceException exceptions on the line if (foosDictionary.TryGetValue(id, out var foo)) and I cannot in any way reproduce the issue.
Stack trace:
System.NullReferenceException: Object reference not set to an instance of an object.
at MyProject.Service.Baz(Guid id) in CustomClass.cs:line 900
at MyProject.Service.BazFeature(Guid id) in CustomClassCaller.cs:line 288
line 900 is the line in question. It is a direct reference to the dictionary: if (foosDictionary.TryGetValue(id, out var foo)).
Below is the code that leads to the problem line:
public Foo Baz(Guid id)
{
Func<Task<Dictionary<Guid, Foo>>> createDictionary =
async () => (await repository.GetFoos()).ToDictionary(sm => sm.Id);
var foosDictionary = await _cache.GetOrCreateAsync<Dictionary<Guid, Foo>>(
"cacheKey",
async cacheEntry =>
{
cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(15);
return await createDictionary();
});
if (foosDictionary.TryGetValue(id, out var foo))
{
return foo;
}
}
// also there's the remaining code, but it shouldn't execute and it is lower than line 900. Anyway, here it is.
var newDictionary = await createDictionary();
if (newDictionary.TryGetValue(id, out var newFoo))
{
fooDictionary = newDictionary;
return newFoo;
}
throw new Exception("Error");
The Usual Suspects are:
await repository.GetFoos() - it uses Dapper.QueryAsync method to get IEnumerable<Foo> and it can't return null. Anyway, I tried hardcoding null return - and goes the next step
.ToDictionary() - it will throw on null. And it does if I hardcode the null return. Also it has different stacktrace and points to GetOrCreateAsync, not the line of code in question.
GetOrCreateAsync - all the other suspects will throw and give different stack trace so this must be it. This method returns null, but I can't figure out how and why.
Like, if there is null on the cache key, it should go and create the value. createDictionary can't return null so it's out of the question. So...how does that even happen? Why?
Memory cache is registered in Startup like this: services.AddMemoryCache(). I don't know whether it's Scoped or Singleton and the Microsoft docs don't address it in a straightforward way.
The app is ASP.NET Core 3.1, GetOrCreateAsync extension method is from v6.0.0, but the actual implementation (or so it seems) gets passed as v3.1.0.
How can I resolve the issue? Can GetOrCreateAsync really return null in some cases? If so, how to reproduce them?
PS. I've thought about thread 1 getting the entry and then thread 2 somehow nullifying it, but that shouldn't work since thread 1 already has the reference to the dictionary. Right?

Rhino Mock Test Expected #1, Actual #0 - error

I'm newbie working with Rhino Mock and I'm getting this error that I cannot understand why. Here the test
public void TestGet()
{
var installationReference = new Guid("21D7D135-6E9E-4F92-8313-873CA3ABDCD8");
var study = MockRepository.GenerateMock<IStudy>();
var installation = MockRepository.GenerateMock<IInstallation>();
var license = MockRepository.GenerateMock<ILicense>();
var participant = MockRepository.GenerateMock<IStudyParticipant>();
var clinicalPartner = MockRepository.GenerateMock<IClinicalPartner>();
clinicalPartner.Stub(c => c.FirstName).Return("John");
clinicalPartner.Stub(c => c.LastName).Return("Doe");
installation.Stub(i => i.Reference).Return(installationReference);
license.Stub(l => l.Installations).Return(new List<IInstallation> { installation });
participant.Stub(p => p.Licenses).Return(new List<ILicense> { license });
participant.Stub(p => p.ClinicalPartner).Return(clinicalPartner);
participant.Stub(p => p.ClinicalPartnerStatus).Return(ClinicalPartnerStatus.Active);
study.Stub(s => s.Description).Return("Test WebAPI");
study.Stub(s => s.Participants).Return(new List<IStudyParticipant> { participant });
repository.Stub(r => r.Query(Arg<GetStudiesByInstallationReference>.Matches(s => s.InstallationReference.Equals(installationReference))))
.Return(new DummyResult<IStudy>(study));
repository.Expect(r => r.Query(Arg<GetStudiesByInstallationReference>.Matches(s => s.InstallationReference.Equals(installationReference)))).Return(new DummyResult<IStudy>(study)).Repeat.Once();
repository.VerifyAllExpectations();
}
My GetStudiesByInstallationReference.cs
public class GetStudiesByInstallationReference : IQuery<IStudy>
{
public Guid InstallationReference { get; set; }
public GetStudiesByInstallationReference(Guid installationReference)
{
InstallationReference = installationReference;
}
public IQueryResult<IStudy> Execute(ISession session)
{
var criteria = session.CreateCriteria<IStudy>();
criteria.CreateAlias("participants", "p");
criteria.CreateAlias("p.licenses", "l");
criteria.CreateAlias("l.installations", "i");
criteria.Add(Restrictions.Eq("i.Reference", InstallationReference));
criteria.Add(Restrictions.Eq("Status", StudyStatus.Approved));
criteria.Add(Restrictions.Eq("p.ClinicalPartnerStatus", ClinicalPartnerStatus.Active));
criteria.Add(Restrictions.Le("StartDate", DateTime.Now));
criteria.Add(Restrictions.Or(
Restrictions.IsNull("EndDate"),
Restrictions.Gt("EndDate", DateTime.Now)));
return new CriteriaResult<IStudy>(criteria);
}
}
I want to test GetStudiesByInstallationReference was called one time.
What am I doing wrong?...it should pass the test as the Expect clause is the same used in the Stub but I still got the exception
Expected #1, Actual #0.
Anybody could help me with this?
Thanks in advance
I want to test GetStudiesByInstallationReference was called one time.
GetStudiesByInstallationReference is a type, and not a method that you expect to be called.
repository
.Expect(r => r.Query(Arg<GetStudiesByInstallationReference>.Matches(s => s.InstallationReference.Equals(installationReference))))
.Return(new DummyResult<IStudy>(study)).Repeat.Once();
This line from your code is setting up an expectation on the repository mock. It expects that the Query() method is called with a parameter of type GetStudiesByInstallationReference that has the correct installation reference GUID as a property. If this method isn't called with the correct parameter, you will get the error you describe when calling repository.VerifyAllExpectations().
It looks like your test is missing the actual call to the SUT i.e. the "Act" in Arrange/Act/Assert. Simply put, you need to execute some code that will cause the method on your repository to be called as you expect (or change the test).

Error: DbContext has been disposed

public JsonResult JTask(int id)
{
using (TestDb db = new TestDb())
{
var a = db.ToDos.Where(todo => todo.UserId == id);
return Json(a, JsonRequestBehavior.AllowGet);
}
}
I have a problem with returning JsonResult
When I run this code code I get the error
"The operation cannot be completed because the DbContext has been
disposed."
I tried adding .ToList() at the end of the line 3, as was suggested, but then I got the error
"A circular reference was detected while serializing an object of type
System.Data.Entity.DynamicProxies."
It's not very obvious, but the built-in Json method only does the serialization after the JTask method has finished executing. By that time, of course, the context has been disposed, resulting in the original error you are describing.
If you have an ICollection<TodoItem> property inside your Todo class, each of those will have a ToDo property which is a reference back to the parent. And each of those ToDo properties will also have ICollection<TodoItem> children, which has a reference back to the parent again, and so on and so forth. This can potentially loop for infinity, and when the serializer tries to serialize the object, it gives up with a circular reference error.
One way to solve both of these problems at the same time is by using viewmodels. A viewmodel is an intermediate class that holds only a subset of the properties that a model class has. The typical flow is for the model class to get converted to a viewmodel first, then it would be the viewmodel that gets serialized as json:
var viewModels = new List<TodoViewModel>();
using (TestDb db = new TestDb())
{
var todoModels = db.ToDos.Where(todo => todo.UserId == id).ToList();
foreach (var model in todoModels)
{
var todoViewModel = new TodoViewModel
{
// Populate viewmodel properties here
Text = model.Text
};
viewModels.Add(todoViewModel);
}
}
return Json(viewModels, JsonRequestBehavior.AllowGet);
I wrote a blog post about the advantages of using viewmodels. You can check it out here if you're interested: Why Use ViewModels
Because Linq is Lazy by the time the JSON tries to get the data out of a (and only then actually goes to db) the db has already been disposed - when leaving the scope of the using
public JsonResult JTask(int id)
{
using (TestDb db = new TestDb())
{
var a = db.ToDos.Where(todo => todo.UserId == id).ToList();
return Json(a, JsonRequestBehavior.AllowGet);
}
}
var a = db.ToDos.Where(todo => todo.UserId == id).ToList();

Unit Test Using Moq

I am unit-testing an async method that returns a List<T>. This method has a dependency on a mapping class/interface. In my unit-test, I am mocking the mapping class using moq. The test runs okay, and the returned list has items, but the values of the items is null. I think the problem is because I haven't stubbed-out the mapping classes methods properly. I don't have a lot of experience with testing, so any guidance is appreciated.
Test Method:
[TestMethod]
[TestCategory("CSR.Data.Tests.Services.ServiceSearchTest")]
public void SearchAccount()
{
// Arrange
var mapper = new Mock<CSR.Data.Mapping.Interfaces.IMapper<Account, AccountDTO>>();
mapper.Setup(i => i.Initialize());
mapper.Setup(i => i.ToDomain(It.IsAny<AccountSearchResult>())).Returns(It.IsAny<Account>);
mapper.Setup(i => i.DomainToDto(It.IsAny<Account>())).Returns(It.IsAny<AccountDTO>);
var service = new ServiceSearch(null,mapper.Object);
string accountNumber = "123";
string accountName = "";
// Act
var results = service.SearchAccount(accountNumber, accountName);
// Assert
Assert.IsTrue(results.Result.Count >= 1);
}
Method/Class That I'm Testing:
public class ServiceSearch : IServiceSearch
{
public ServiceSearch(IMapper<Claim, ClaimDTO> claimMapper, IMapper<Account, AccountDTO> accountMapper)
{
_claimMapper = claimMapper;
_accountMapper = accountMapper;
}
public async Task<List<AccountDTO>> SearchAccount(string accountNumber, string accountName)
{
var accounts = new List<Account>();
var accountDTOs = new List<AccountDTO>();
var results = await Task.Run(() => base.AccountSearch(accountNumber, accountName).Result);
if (results != null && results.Count > 0)
{
//Map DH to Domain
_accountMapper.Initialize();
foreach (AccountSearchResult result in results)
{
accounts.Add(_accountMapper.ToDomain(result));
}
//Map Domain to DTO
foreach (Account account in accounts)
{
accountDTOs.Add(_accountMapper.DomainToDto(account));
}
}
return accountDTOs;
}
}
This isn't the best place to use a Mock object because you are going to spend a lot of time writing your test objects and mock results. The issue with the setup call is that you haven't configured anything to send back in the result. A correct example would be:
// you would fully configure this object
AccountDTO expectedResult = new AccountDTO();
mapper.Setup(i => i.ToDomain(It.IsAny<AccountSearchResult>())).Returns(expectedResult);
Now you can use the setup to configure different accountDTOs for different inputs.
You call also configure a callback to generate the account at test time:
mapper.Setup(i => i.ToDomain(It.IsAny<AccountSearchResult>())).Returns<AccountSearchResult>(sr => {
// build and return your dto here
});
However, unless your mapper is expensive to run or create, I think you'd better off just ensure that it is fully tested and acceptable and then use it to go ahead and generate the DTOs directly instead of trying to mock it out.
You don't actually setup an object in the ".Returns" call. You need to make sure to setup the ".Returns" to actually have an object with values.

NHibernate ClassMap<T> code not executing

I'm setting up a new project and have gotten NHibernate to work with structuremap...sorta. I'm using the NHibernate.Mapping.ByCode.Conformist setup with ClassMaps. No errors occur, but when I query over a session and there are records present in the database for a particular type, nothing comes back. Upon further examination, it appears that the mappings that I've set up for these types are not executing. Here's my code that wires up things for structuremap. I can confirm that it is being executed.
public class OrmRegistry : Registry
{
public OrmRegistry()
{
var sessionFactory = BuildSessionFactory();
For<ISessionFactory>().Singleton().Use(sessionFactory);
For<ISession>().HybridHttpOrThreadLocalScoped().Use(s => sessionFactory.OpenSession());
}
public ISessionFactory BuildSessionFactory()
{
var cfg = new Configuration().DataBaseIntegration(db =>
{
db.ConnectionStringName = "LocalSqlServer";
db.Dialect<MsSql2008Dialect>();
db.Driver<SqlClientDriver>();
db.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
db.IsolationLevel = IsolationLevel.ReadUncommitted;
db.BatchSize = 500;
}).AddAssembly(Assembly.GetExecutingAssembly());
if(HttpContext.Current != null)
{
cfg.CurrentSessionContext<WebSessionContext>();
}
else
{
cfg.CurrentSessionContext<ThreadStaticSessionContext>();
}
return cfg.BuildSessionFactory();
}
}
I'm nearly certain I'm just missing something extremely obvious here, but I've been looking at it for a few hours and haven't had any success. I also got downsized a couple days ago, so I don't have a coworker around to look at it.
Looks like you got your configuration initialized, but what about mapping? You need to initialize mappings like this (if you are using conventions):
var mapper = new ConventionModelMapper();
// TODO: define conventions here using mapper instance
// just an example on how I have been using it
var entities = ... // get all entity types here
cfg.AddDeserializedMapping(mapper.CompileMappingFor(entities), "MyMappings");
return cfg.BuildSessionFactory();
And another example if you are using mapping classes (from this post):
var mapper = new ModelMapper();
var mappingTypes = typeof (InvoiceMapping).Assembly.GetExportedTypes()
.Where(t => t.Name.EndsWith("Mapping")).ToArray();
mapper.AddMappings(mappingTypes);
cfg.AddMapping(mapper.CompileMappingForAllExplicitlyAddedEntities());
return cfg.BuildSessionFactory();

Categories