0

I’ve been tasked with converting some code we have in MVC from .NET Framework to .NET Core. The code dynamically binds a View to the appropriate Model based on a simple pattern. The View name is the first field in the page that is transmitted. For example, if the first data field is PAGE1 then there is a corresponding Model named PAGE1Model. The code does the dynamic binding by using ModelBindingContext(). This code works perfectly in .NET Framework but syntaxes in .NET Core.

I tried writing what I thought would be the equivalent in .NET Core. It compiles but it doesn't work. As I understand it, on the surface binding in .NET Core and Framework produce the same results but inside they’re different and I think that’s what’s causing the problem. Since I’m new to .NET Core I’ve spent 3 days searching for some code that will dynamically assign a Model to a Binder but every example I can find dynamically changes something within the View or Model but assumes the View and Model themselves are fixed.

This is the code that works in .NET Framework

private void BindModel(MapModel pModel)
    {
        Type ModelType = pModel.GetType();
        // bind model data
        var binder = Binders.GetBinder(ModelType);
        ModelBindingContext bindingContext = new ModelBindingContext()
        {
            ModelMetadata = 
              ModelMetadataProviders.Current.GetMetadataForType(() 
           => pModel, ModelType),
            ModelState = ModelState,
            ValueProvider = new FormValueProvider(this.ControllerContext)
        };
        binder.BindModel(ControllerContext, bindingContext);
    }

The input is the name of the Map + "Model" e.g. BindModel(Map1Model)

My one attempt at .NET Core, which doesn't work, is

public class ModelBinder : IModelBinder
{
    public ModelBinder(MapModel pModel, ControllerContext pContext)
    {
        model = pModel;
        context = pContext;
    }
    MapModel model;
    ControllerContext context;
    private readonly IModelBinder thisBinder;
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }
        bindingContext.Model = model;
        bindingContext.ValueProvider = (IValueProvider) context;
        return Task.CompletedTask;
    }
}

and the new call is

ModelBinder BindModel = new ModelBinder(Model, this.ControllerContext);

I expected this would accomplish the same thing as the .NET Framework code but it isn't doing anything because the BindModelAsync task is never being run.

The application is a legacy application moved to C# .NET from mainframe COBOL so I’m constrained in that I can’t change the input format or the correspondence between View name and Model name.

2
  • What do you mean by dynamic binding? Binding is dynamic by default in Core. Commented Jun 13, 2019 at 19:54
  • 1
    The most common occurrence in a Controller is for the names of the View and the Model to be specified at compile time. I'm using dynamic binding to indicate that the View and the Model are specified at run time and will change from one transaction to another. Commented Jun 14, 2019 at 20:32

2 Answers 2

2

The accepted answer re-written to be non-blocking in modern C# syntax

public async Task<IActionResult> Action() {
    // ...
    if (ModelState.IsValid)
    {
        var result = await TryUpdateModelAsync(Model, Model.GetType(), "");
        if (!result)
           throw new Exception("TxServerController.TxMap: TryUpdateModelAsync failed");
    }
    ModelState.Clear();
}
Sign up to request clarification or add additional context in comments.

Comments

-1

For the benefit of anyone else who has a similar problem, here is the code I came up with that actually works:

if (this.ModelState.IsValid)
            {
                Task<bool> task = this.TryUpdateModelAsync(Model, Model.GetType(), "");
                task.Wait();
                if (!task.Result)
                    throw new Exception("TxServerController.TxMap: TryUpdateModelAsync failed");
            }
            this.ModelState.Clear();

3 Comments

Have you use the await keyword before?
In this case wait is the necessary keyword since the completion of the binding is required before any subsequent code can be executed.
That's what await does. await waits without blocking the thread. Wait() waits too but blocks. stackoverflow.com/questions/13140523/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.