Trying to understand the controller of MVC - c#

I'm new to C#, and when i opened the Controller of a MVC project(ASP.NET), i have found the following syntax:
public class CategoriasController : Controller
{
private readonly ApplicationDbContext _context;
public CategoriasController(ApplicationDbContext context)
{
_context = context;
}
I'm sorry to ask, but what's happening on line 3?
private readonly ApplicationDbContext _context;
Is _context a variable? An object? That's the same of saying _context = new ApplicationDbContext?
Sorry for the question, I've searched the Microsoft docs, but couldn't find any answer.

The MVC model as a whole when implemented in C# is a little interesting, but does work very well.
When a request is made, the path of the request is used by the routing mechanism to use reflection to instantiate a class capable of handling the response.
In this case, when a matching ActionResult method name matching the CategoriasController class name, for example /Categorias/Fiction is used, then the matching controller class will be instantiated via reflection.
Once the class is instantiated, the method is called. During class instantiation, normal things occur that occur with any other class. So, what you see here, is the availability of a class level member _context. Looking further, you can see that there is a constructor which can be called with a context as well. That is known as inversion of control, and is accomplished with a dependency injection container. This means that during the instantiation from reflection, a fully instantiated context (for querying a database) is also created and then passed in. In MVC the DI container is often defined in the global.asax.cs file.
Once the class is instantiated, and the member method called, the return view essentially creates a string writer to be written to the response stream, and MVC's job is done.

This ensures that the class level variable _context can only be set in the constructor and cannot otherwise be changed. In the context of accessing a database as here you do not want the class methods to be able to change this, only to use.
The the c# documentation for readonly here it states "In a field declaration, readonly indicates that assignment to the field can only occur as part of the declaration or in a constructor in the same class."

Related

How do modify database initializer Seed method when using Repository and UnitOfWork patterns in MVC5 ASP.Net application?

I've had a look through the tutorial
https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
(I'm actually using MVC5 and even that's old now!! - The MVC5 version of the same tutorial didn't go into repository and unit of work much).
I've implemented the patterns as described, and replaced the code in my controllers, but am left puzzling over my Database Initializer that I created earlier in the tutorial.
It has a method
protected override void Seed( MyContext context )
It seems now that I ought to be changing the code here to use UnitOfWork too, rather than MyContext
I can't do that though, because this is an overridden method and I guess the method signature has to be just as it is to be called at the right time.
Further, the instance of MyContext that is in UnitOfWork is private, so even if I could pass a unit of work in I still couldn't use its context.
So the question is once you've done this and implemented Repository and UnitOfWork, how do you fix up this initialization code, or how else do you initialize your database with seed data?
So, I think this was a bit of n00b error on my part, and some of you that had looked at this probably wondered what on earth I was on about, but I'll leave this answer here just in case it helps anyone else.
Following the tutorial I'd created a
public class GenericRepository<TEntity> where TEntity : class
{
internal PayloadContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository( PayloadContext context )
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
....
}
And I hadn't really looked closely enough at that second line in the constructor.
I'd seen that the context was now created in th UnitOfWork, and passed into the various repositories so that all the repositories could share it.
But I'd thought, incorrectly, that what was happening above was the a DbSet was being created for this repository. Therefore I removed the declaration of the DbSet properties from my context, thinking I'd never use them, and that I'd now be accessing the data through the repositories.
In other words in the controllers, for example, I thought I was never doing:
MyContext db = new MyContext();
and
public ActionResult Index()
{
return View( db.MySetPropertyDeclaredInMyContext.Get() )
}
but rather
private UnitOfWork unitOfWork = new UnitOfWork();
and
public ActionResult Index()
{
return View( unitOfWork .MySetPropertyDeclaredInMyUoW.Get() )
}
By the time I got back to "fixing up" the initialisation code I was was stuck because that had the context passed in and the "old" entity sets directly referenced. Further I don't call the Seed method myself from my own code.
What I realised is that the second line in the constructor of the GenericRepository was only setting a reference to a DBSet (that's a method, not a 'new'). What's more "Entity Framework requires that this method return the same instance each time that it is called for a given context instance and entity type."
With that in mind, I still needed my original DbSet property declarations inside the context.
The DatabaseInitializer Seed method could remain unchanged.
For completeness, for those wondering where this is called:
An implementation of this interface [IDatabaseInitializer] is used to initialize the underlying database when an instance of a DbContext derived class is used for the first time. This initialization can conditionally create the database and/or seed it with data. The strategy used is set using the static InitializationStrategy property of the Database class
So in other words, this initialisation code was fine and would be triggered first time the context was used which would be first time a UnitOfWork was performed. (Or maybe even invoked).

How to determine which constructor Autofac uses when resolving

I'm using a custom JsonConverter and JsonSerializerSettings.TypeNameHandling = TypeNameHandling.Objects to create the required instances during deserialization. The instances are created by resolving the types from an Autofac IOC container. Everything works fine, except...
I have several "core objects" that request a unique Id in the constructor from a service (which is correctly injected into the constructor). When deserializing this should not happen because it is fairly expensive and the Ids will be populated from the Json file anyway once the instance has been created.
Currently, when resolving from within the custom JsonConverter I'm using _scope.Resolve<T>(new TypedParameter(typeof(IIdService), null)); to then - in the called constructor - check for null and act accordingly.
Some people apparently consider multiple constructors worse than a code-smell when using an IOC (which makes me wonder why Autofac offers several features regarding the topic), but in the context of deserialization I think it can make perfect sense.
As far as I can tell Autofac has mechanisms to decide which constructor to use during registration, but not when resolving. My preferred solution would be to add a custom attribute to a constructor (e.g. [CtorForDeserializing]) and use that for deciding. Is that possible?
There are a couple of extension points Autofac has for reflection-based activations but doesn't have well documented yet that may help you out: IConstructorFinder and IConstructorSelector.
IConstructorFinder is used to locate all the available constructors on a type. The core example is the DefaultConstructorFinder which locates only public constructors. If you wanted to, say, hide constructors with particular attributes or start finding internal/private constructors, you could create a custom finder. This really only happens once so you don't get to make runtime choices here.
IConstructorSelector is used to choose, at resolve time, which constructor should be used to instantiate the object. There are a couple of these in core Autofac, but the primary example is the MostParametersConstructorSelector which selects the constructor that has the most available matching parameters at the time. Constructors get found by the IConstructorFinder and then that set of constructors is what is presented to the IConstructorSelector to choose from. This is where you could make more runtime choices since it happens every time the object is resolved.
There are extension methods to help you add your finder/selector to a registration:
builder.RegisterType<MyType>()
.FindConstructorsWith(new MyConstructorFinder())
.UsingConstructor(new MyConstructorSelector());
You don't have to customize both things, you can just do one or the other if you want. I'm just showing you the extensions.
Actually Autofac is able to decide which constructor to use both ways - during registration or resolution. For resolution part here is the quote from documentation: "Autofac automatically uses the constructor for your class with the most parameters that are able to be obtained from the container" (see here).
Consider following example.
public interface ISomeService
{
Guid Id { get; }
}
public class SomeService : ISomeService
{
public Guid Id { get; }
public SomeService()
{
Id = Guid.NewGuid();
}
public SomeService(Guid id)
{
Id = id;
}
}
// Startup.cs:
builder.RegisterType<SomeService>().As<ISomeService>().InstancePerLifetimeScope();
// TestController.cs:
[Route("api/[controller]")]
public class TestController : Controller
{
private readonly IComponentContext _context;
public TestController(IComponentContext context)
{
_context = context;
}
[HttpGet]
public IActionResult Get()
{
var service = _context.Resolve<ISomeService>();
return Ok(service.Id);
}
[HttpGet("{id}")]
public IActionResult Get(Guid id)
{
var service = _context.Resolve<ISomeService>(new NamedParameter("id", id));
return Ok(service.Id);
}
}
// GET http://localhost:5000/api/test/e0198f72-6337-4880-b608-68935122cdea
// each and every response will be the same: e0198f72-6337-4880-b608-68935122cdea
// GET http://localhost:5000/api/test
// this way it responds with some random guid each time endpoint is called
Travis Illig sent me in the right direction - thanks!
I ended up implementing a solution around the following details:
Implement custom attributes, e.g.: public class DeserializeCtorAttribute : Attribute { }, which will be used by the (also to be implemented) IConstructorFinder.
Implement an empty generic interface, e.g.: IDeserializable<T>, which will be used for resolving the services/components.
Let relevant component classes implement the interface (MyClass : IDeserializable<MyClass>) and add an extra registration for the component:
_builder.RegisterType<MyClass>().As<IDeserializable<MyClass>>()
.FindConstructorsWith(MyConstructorFinder);
Use the implemented DeserializeCtorAttribute in the desired constructor of MyClass.
Let the JsonConverter create the required instance by calling (MyClass) scope.Resolve(IDeserializable<MyClass>); casting is required, but safe. Due to the registration the instance will be created using the desired constructor.

How to use a dbcontext in a static class? (ObjectDisposedException)

Hey I just recently learnt how to use extension methods and pretty excited to implement it in my current project.
My objective:
I want to check whether an entry exists in my table in a helper class, since I'm going to use it in multiple controllers to be able to determine which navigation links to show in my navbar:
My Issue:
I don't know how to access my dbcontext in my static helper class. My dbcontext controller takes an argument I don't know how to pass in my static class. I think creating a new dbcontext would solve my scope issue explained below but I don't see how I can pass the optional argument to my constructor.
It is currently configured in the Startup.cs class.
What I tried:
Passing the ApplicationDbContext as an argument. This works for a single method call in my controller, but when calling multiple extension methods (To check which game accounts the user has) I get a ObjectDisposedException.
ObjectDisposedException: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'ApplicationDbContext'.
From what I understand it is a scope issue where the first method call disposes the context when it's done and I'm trying to use the same context in the next call? What can I do to work around that?
I tried reading this link Cannot access a disposed of object in ASP.NET Core when injecting DbContext but it didn't help me since it requires the ApplicationBuilder which is in the Startup.cs class.
Solution Update
I disposed the dbcontext after every method call because I put it into a variable. Instead, I call it directly on the passed context and it works:
Yeah, so, although the extensions are new and shiny to you, that doesn't mean you should use them for everything. First, extensions should have a logical connection to the type they're operating on. For example, if you have a string, something like ToUpper() makes sense as an extension because it modifies and returns a string. Something like what you're trying to do: just using the value of the reference to return a completely foreign type is a violation of the extension pattern.
Second, an extension should not interact with something like a database. In particular here, the static nature of an extension is completely incompatible with the concept of a EF context object. The only way you could even get it to work is to actually new up a context each time the extension is called, inside the extension. That's both a great way to screw up the EF object tracking stuff and a great way to leak memory.
Long and short, don't do this.
If you're just trying to factor out this code, you have better options. For example, you can actually just add methods directly to your context.
public class ApplicationDbContext : DbContext
{
...
public bool HasDota2Account(string id)
{
return Dota2Accounts.Any(m => m.ApplicationUserId == id);
}
}
Then, in your controller, you can simply do:
var hasDota2Account = context.HasDota2Account(User.Identity.GetUserId());
Never declare DbContext as static, it will cause all sorts of trouble, and not refresh the data, so you will be getting old data from a query. An option is to instantiate it inside the static method every time you use it, like this:
public static MyClass Example
{
public static bool MyStaticMethod(long id)
{
MyDBContext db = new MyDBContext();
//use db context now....
}
}

Is Ninject creating 2 separate context?

I'm creating a Web API and I'm using dependency inject wit Ninject.
I have:
IRTWRepository
IModelFactory
I'm injecting those 2 into my controllers like this.
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IRTWRepository>().To<RTWRepository>();
kernel.Bind<RTWAPIContext>().To<RTWAPIContext>();
kernel.Bind<IModelFactory>().To<ModelFactory>();
}
My RTWRepository constructor looks like this
public class RTWRepository :IRTWRepository
{
private RTWAPIContext _context;
public RTWRepository(RTWAPIContext context)
{
_context = context;
}}
My ModelFactory constructor looks like this
public class ModelFactory : IModelFactory
{
private IRTWRepository _repo;
public ModelFactory(IRTWRepository repo)
{
_repo = repo;
}
}
I have a Controller that looks like this:
public MaterialsController(IRTWRepository repository,IModelFactory modelFactory)
: base(repository,modelFactory)
{
}
Now, my question is : Is Ninject creating 2 separate contexts when creating an instance of my RTWRepository and also when creating an instance of ModelFactory?.
The reason that I'm asking that is because I'm having a problem when I try to save an entity that has a dependency to another object which was previously retrieve from the db.
I'm saving the entity in my controller but I'm creating it in my model factory along with is dependency.
public class RecycleCenter
{
public RecycleCenter()
{
}
public int MyProperty { get; set; }
[Required]
public virtual Address Address { get; set; }
}
The code above is for the entity Recycle Center which has an Address, this recycle center entity is created in my model factory and then in my controller I try to save it but when my repository execute this line
_context.RecycleCenters.Add(entity);
I'm getting this error
An entity object cannot be referenced by multiple instances of IEntityChangeTracker
So, somewhere in my code I'm using 2 context instead of 1 and I think is when creating the ModelFactory and RTWRepository, is this assumption correct?, if so how do I fix it?
TL;DR;
You probably need to change this line:
kernel.Bind<RTWAPIContext>().To<RTWAPIContext>();
to
kernel.Bind<RTWAPIContext>().To<RTWAPIContext>().InRequestContext();
Explanation:
When you define a binding in Ninject, you also specify how that object's lifecycle should be handled.
If you don't explicitly define it, Ninject's default lifecycle is Transient. Transient means that each time an instance is required, it will create a new one. In your case, you need to two instances: one for the RTWRepository of the ModelFactory and one for the RTWRepository of the MaterialsController.
You can modify the lifestyle to one of these options:
Singleton ==> kernel.Bind<RTWAPIContext>().To<RTWAPIContext>().InSingleTonScope();
Request ==> kernel.Bind<RTWAPIContext>().To<RTWAPIContext>().InRequestScope();
Thread ==> kernel.Bind<RTWAPIContext>().To<RTWAPIContext>().InThreadScope();
Named, Call, Parent, Custom
In your case, I think you need InRequestScope, but you have to check the necessary lifecycle as it depends on the application.
For further information please check out the documentation here: https://github.com/ninject/ninject/wiki/Object-Scopes
Most probably, it is. There's no annotation that is telling to Ninject "Hey, stop, when you have created the instance once, reuse it". You should agree that in most cases, you would want multiple instances of an object and that it is a rare case, where you want it only once.
If you want to reuse the instance, use the singleton pattern. Ninject is familiar with it, so you can bind the object mapping to a method
kernel.Bind<RTWAPIContext>().ToMethod(c => RTWAPIContext.GetInstance());
There is also a ToSingleton binding, but I bet you cannot make your context constructor private and implement C# specific singleton due to other ASP.NET problems (e.g. ASP.NET Identity will try to invoke the context's method for object creation).

Passing web context to a 'service' in ASP MVC app

I'm trying to work out a way of passing the web current http context to a service class (or initialising the class with a reference to it). I am doing this to abstract the rest of the app away from needing to know anything about the http context.
I also want the service to be testable using TDD, probably using one of the Mockable frameworks. Hence it would be preferable to use an interface rather than an actual class.
An example of what I'd like to achieve:
class WebInstanceService
{
private IHttpContext _Context;
public WebInstanceService( ... , IHttpContext HttpContext )
{
....
_Context = HttpContext;
}
// Methods...
public string GetInstanceVariable(string VariableName)
{
return _Context.Current.Session[VariableName];
}
}
One of the main issues I have is that there is no IHttpContext, the .net http context is a subclass of an abstract class which can't be mocked (easily?).
Another issue is that I can't initialise global instances of the class as then the context won't be relevant for most requests.
I could make the class static, and require the Context to be passed to each function as it is called i.e.
public static string GetInstanceVariable(string VariableName, HttpContext Context)
{ ... }
but this doesn't make the class any easier to test, I still need to create an HttpContext and additionally any non-web-aware services which want to use this class suddenly need to be able to retrieve the Context requiring them to be closely coupled to the web server - the whole reason for wanting to create this class in the first place.
I'm open to ALL suggestions - particularly those which people know facilitate easy tdd testing. How would people suggest I tackle this problem?
Cheers
This is why HttpContextBase and HttpContextWrapper were introduced. You probably want to use HttpContextBase and when passing the real context in, use new HttpContextWrapper( httpContext ), although, I think that what is available to you in the controller is already of type HttpContextBase. I would create one of these in my controller each time rather than trying to reference the current context from the static, global HttpContext.Current instance. If you need it in your view, pass a reference to your strongly typed context in ViewData.
I mock up HttpContextBase frequently in my tests.
class WebInstanceService
{
private HttpContextBase _Context;
public WebInstanceService( ... , HttpContextBase HttpContext )
{
....
_Context = HttpContext;
}
// Methods...
public string GetInstanceVariable(string VariableName)
{
return _Context.Session[VariableName];
}
}
What we do is spin one of these up http://haacked.com/archive/2007/06/19/unit-tests-web-code-without-a-web-server-using-httpsimulator.aspx
Easy as pie, just instanciate an HttpSimulator and fill in the values, and HttpContext.Current gets filled up with whatever you specify.
IHttpContext is something that is in MVC, and aparently one day will be in webforms. Hopefully that day will be .net 4
ASP.NET comes with System.Web.Abstractions that include HttpContextBase that you can use for dealing with the HttpContext in a testing situation.
I would personally abstract away the direct dependency on the HttpContext.

Categories