[RESOLVED]Accessing DB Context from Model Binder

When creating a scaffolded controller with VS, the db context member gets marked as private, like so:

public class TransferController : Controller
{
    private TransferDBContext db = new TransferDBContext();

    // ...
}

Is there a specific reason for this?  Are there any risks (e.g. resource leaks) associated with making this public and accessing it from other classes?

I ask because I have a model set up like so:

public class Transfer
{
    [Column("SEND_BY")]
    public int SendByID { get; set; }

    [ForeignKey("SendByID")]
    public User SendByUser { get; set; }

    [Column("RECV_BY")]
    public int? RecvByID { get; set; }

    [ForeignKey("RecvByID")]
    public User RecvByUser { get; set; }

    // ...
}

I’m able to fetch SendByUser and RecvByUser when querying my db context with .Include(), but these two properties aren’t getting filled when the model is bound from a POST request.  If it’s kosher for the controller’s DB context to be public (Or to have
a public getter), binding the user properties is as simple as creating and registering the following TransferModelBinder.cs:

public class TransferModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        Transfer model = (Transfer)base.BindModel(controllerContext, bindingContext);
        TransferController controller = (TransferController)controllerContext.Controller;

        model.SendByUser = controller.DB.Users.SingleOrDefault(i => i.UserID == model.SendByID);
        if (model.RecvByID != null)
        {
            model.RecvByUser = controller.DB.Users.SingleOrDefault(i => i.UserID == model.RecvByID);
        }

         return model;
    }
}

Is this an acceptable way to bind those properties?  Is there a better way?

It being marked as private is just going to ensure that it is only accessed within the class that it is defined in (e.g. your TransferController) and that a new one will be instantiated each time that your controller is created.

If you wanted to access it the way that your code demonstrates below :

model.SendByUser = controller.DB.Users.SingleOrDefault(i => i.UserID == model.SendByID);

Then you would likely need to mark it as public in order to access it in this way. Personally, when it comes to usage, I’m a big fan of using the "using" syntax to create and dispose of my context after each usage which might look like the following :

public class TransferModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        Transfer model = (Transfer)base.BindModel(controllerContext, bindingContext);
        
        using(var context = new TransferDBContext())
        {
             model.SendByUser = context.Users.SingleOrDefault(i => i.UserID == model.SendByID);
             if (model.RecvByID != null)
             {
                  model.RecvByUser = context.Users.SingleOrDefault(i => i.UserID == model.RecvByID);
             }
        }

        return model;
    }
}

This wouldn’t require you to have your TransferDBContext defined within your actual Controller.

Rion Williams

[A] new one will be instantiated each time that your controller is created.

Is there an advantage to creating a new DB context there, rather than just pointing to the one that already exists in the controller? (Other than not having to change the scaffolded accessibility, of course.)

Is there any overhead associated with creating a new DB context that I should be concerned with avoiding?

FYI, I’ve got the "public getter" option in play for the moment, since there’s certainly no reason an external class would need to change my controller’s db context to point to something else:

private TransferDBContext db = new TransferDBContext();
public TransferDBContext DB
{
    get
    {
        return db;
    }
}

Leave a Reply