Я пытаюсь решить проблему наследования при отправке данных в контроллер с помощью 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,
Теперь, если мы добавим еще один класс, который имеет список объектов 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,