Невозможно применить привязку модели с наследованием интерфейса

Я пытаюсь решить проблему наследования при отправке данных в контроллер с помощью Custom Model Binder. Я нашел несколько сообщений в блогах и сообщения о переполнении стека, которые объяснили похожие сценарии. Например: https://stackoverflow.com/questions/7222533/polymorphic-model-binding/7222639#7222639

Мои тесты показывают, что в некоторых случаях эти решения работают нормально. Однако есть определенные случаи, когда эти решения терпят неудачу, и я пока не могу найти решение.

Давайте попробуем создать простой сценарий (извиняюсь, что вопрос стал длинным, но я попытался объяснить каждую деталь). У нас есть перечисление типов соединений

public enum ConnectionType
{
    ConnectionSQL,
    ConnectionOracle
}

Давайте наследовать Наследие

public interface IConnectionDatabase
{
    ConnectionType Type { get; }
}

public class ConnectionSQLDatabase : IConnectionDatabase
{
    public ConnectionType Type => ConnectionType.ConnectionSQL;
}

public class ConnectionOracleDatabase : IConnectionDatabase
{
    public ConnectionType Type => ConnectionType.ConnectionOracle;
}

и, наконец, класс как следующий

public class DataSource
{
    public IConnectionDatabase DataBase { get; set; }
}

И действие контроллера

public ActionResult AddDataSource(DataSource dataSource)
{
    // more details not required
}

который отлично работает с этой моделью Binder

public class ConnectionDatabaseModelBinder : DefaultModelBinder
{
  public override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
  {
       if (modelType != null && bindingContext != null && modelType.Equals(typeof(IConnectionDatabase)))
        {
            try
            {
                // get the correct connection type
                string connectionTypeString = bindingContext.ValueProvider.GetValue("Type");
                ConnectionType connectionType = (ConnectionType)Enum.Parse(typeof(ConnectionType), connectionTypeString, true);
                Type type = connectionType.BuildConnectionType(); // I did some logic here to give the correct class based on the Type

                // Create an instance of the specified type
                IConnectionDatabase connectionDatabase = ClassBuilder.CreateInstance<IConnectionDatabase>(type);

                // Gets metadata for the specified model accessor and model type
                bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, type);
                bindingContext.ModelMetadata.Model = connectionDatabase;
                return connectionDatabase;
            }
            catch (Exception ex)
            {
                // throw Exception here
            }
        }
        else
        {
            // use the default Model Binder
            return base.CreateModel(controllerContext, bindingContext, modelType);
        }
  }
}

Теперь это похоже на работу, когда я вызываю действие контроллера с запросом POST, используя эти данные из JavaScript

var connection = {
  Type = "ConnectionSQL"
}

В этом случае я получаю экземпляр класса ConnectionSQLDatabase в Action Controller. Пока все хорошо!


Теперь, если мы добавим еще один класс, который имеет список объектов DataSource

public class Environment
{
    public List<DataSource> DataSourceList { get; set; }
}

И добавьте еще одно действие контроллера:

public ActionResult AddEnvironment(Environment environment)
{
    // more details not required
}

и данные, отправленные с JavaScript как

var environment = {
    DataSourceList = [
        { Type: "ConnectionSQL" },
        { Type: "ConnectionOracle" },
    ]
}

В этом случае запрос все еще попадает в модель Binder, однако в первой строке метода CreateModel он не работает, заявив, что он не может прочитать ключ с именем «Тип» от поставщика стоимости

И это потому, что сама модель среды не имеет свойства с именем «Тип», но его дети делают.

Я могу настроить Model Binder для обработки этого случая, но, скажем, если я начну добавлять больше классов, которые используют объекты типа DataSource, мне придется начать обработку всех случаев, и это будет беспорядочно.

Есть ли стандартный способ достичь этого?

javascript,c#,inheritance,modelbinders,

0

Ответов: 0


Теперь, если мы добавим еще один класс, который имеет список объектов DataSource

public class Environment
{
    public List<DataSource> DataSourceList { get; set; }
}

И добавьте еще одно действие контроллера:

public ActionResult AddEnvironment(Environment environment)
{
    // more details not required
}

и данные, отправленные с JavaScript как

var environment = {
    DataSourceList = [
        { Type: "ConnectionSQL" },
        { Type: "ConnectionOracle" },
    ]
}

В этом случае запрос все еще попадает в модель Binder, однако в первой строке метода CreateModel он не работает, заявив, что он не может прочитать ключ с именем «Тип» от поставщика стоимости

И это потому, что сама модель среды не имеет свойства с именем «Тип», но его дети делают.

Я могу настроить Model Binder для обработки этого случая, но, скажем, если я начну добавлять больше классов, которые используют объекты типа DataSource, мне придется начать обработку всех случаев, и это будет беспорядочно.

Есть ли стандартный способ достичь этого?

00JavaScript, C #, наследование, modelbinders,
Похожие вопросы