DTO с Simple.OData.Client - PullRequest
       57

DTO с Simple.OData.Client

2 голосов
/ 08 октября 2019

На моем сервере у меня есть следующие настройки:

EntitySet<Contact>("Contacts");
EntityType<ContactDto>();

Вот действия контроллера:

[EnableQuery]
public ActionResult<IQueryable<ContactDto>> Get()
{
  return Ok(_DbContext.Contacts.Select(c => new ContactDto(c)));
}

[EnableQuery]
public async Task<ActionResult<Contact>> Get(int key)
{
  return await _DbContext.Contacts.FindAsync(key);
}

Contact и ContactDto внедряют IContact, кроме того, что онине знают друг друга.

При запросе к серверу (используя маршрут Contacts) я получаю ожидаемый результат, но в клиенте я пытаюсь сделать:

var settings = new ODataClientSettings(new Uri(
    $"https://localhost:{Constants.Port}/{Constants.Api}"));
var client = new ODataClient(settings);

var result = await client
    .For<Contact>()
    .FindEntriesAsync();

И я получаю исключение:

Microsoft.OData.ODataException: 'The context URL 'https://localhost:54687/api/$metadata#Contacts/ODataDtoRepro.Models.ContactDto' is invalid

StackTrace:

at Microsoft.OData.JsonLight.ODataJsonLightContextUriParser.ParseContextUriFragment(String fragment, Func`3 clientCustomTypeResolver, Boolean throwIfMetadataConflict, Boolean& isUndeclared)
   at Microsoft.OData.JsonLight.ODataJsonLightContextUriParser.ParseContextUri(ODataPayloadKind expectedPayloadKind, Func`3 clientCustomTypeResolver, Boolean throwIfMetadataConflict)
   at Microsoft.OData.JsonLight.ODataJsonLightContextUriParser.Parse(IEdmModel model, String contextUriFromPayload, ODataPayloadKind payloadKind, Func`3 clientCustomTypeResolver, Boolean needParseFragment, Boolean throwIfMetadataConflict)
   at Microsoft.OData.JsonLight.ODataJsonLightDeserializer.ReadPayloadStart(ODataPayloadKind payloadKind, PropertyAndAnnotationCollector propertyAndAnnotationCollector, Boolean isReadingNestedPayload, Boolean allowEmptyPayload)
   at Microsoft.OData.JsonLight.ODataJsonLightReader.ReadAtStartImplementation()
   at Microsoft.OData.ODataReaderCore.ReadImplementation()
   at Microsoft.OData.ODataReaderCore.ReadSynchronously()
   at Microsoft.OData.ODataReaderCore.InterceptException[T](Func`1 action)
   at Microsoft.OData.ODataReaderCore.Read()
   at Simple.OData.Client.V4.Adapter.ResponseReader.ReadResponse(ODataReader odataReader, IODataResponseMessageAsync responseMessage)
   at Simple.OData.Client.V4.Adapter.ResponseReader.<GetResponseAsync>d__3.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Simple.OData.Client.ODataClient.<ExecuteRequestWithResultAsync>d__147`1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Simple.OData.Client.ODataClient.<FindAnnotatedEntriesAsync>d__88.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Simple.OData.Client.ODataClient.<FindEntriesAsync>d__89.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Simple.OData.Client.FluentClientBase`2.<FilterAndTypeColumnsAsync>d__91.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Client.Program.<Main>d__0.MoveNext() in D:\Users\Shimmy\Documents\Visual Studio 2019\Projects\ODataDtoRepro\Client\Program.cs:line 16

Я сделал проект репро на GitHub .

Я создал еще одну ветвь репро , которая использует другой подход, так что он использует общий базовый класс, зарегистрированный в модели EDM, вместоинтерфейс. Тем не менее, Simple.OData.Client не может обойти это. Пожалуйста, проверьте также мои комментарии по этой проблеме.

Как мне заставить DTO работать с OData?

Обновление

Возможное решение: использование действий /функции. Попытался поэкспериментировать с ним, но не смог заставить его работать между клиентом и сервером, см. этот ответ для получения дополнительной информации.

1 Ответ

0 голосов
/ 25 октября 2019

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

var edmModel = new ODataConventionModelBuilder();
edmModel.EntitySet<ContactDto>("Contacts");
routeBuilder.MapODataServiceRoute("API Route", Constants.Api, edmModel.GetEdmModel());

и заставив ContactDto расширить контакт

public class ContactDto : Contact

Поскольку контакт является подмножеством контакта dto, он возвращается, как и ожидалосьбез ошибок. Дайте мне знать, если вы хотите, чтобы я отправил код на ваш github.

...