Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix DataServiceContext can't work with POCO's due to Missing IEdmModel #1614

Merged
merged 11 commits into from
Feb 27, 2020
98 changes: 95 additions & 3 deletions src/Microsoft.OData.Client/DataServiceClientFormat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@

namespace Microsoft.OData.Client
{
#region namespaces
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading.Tasks;
using System.Xml;
using Microsoft.OData;
using Microsoft.OData.Edm;

using Microsoft.OData.Edm.Csdl;
#endregion
/// <summary>
/// Tracks the user-preferred format which the client should use when making requests.
/// </summary>
Expand Down Expand Up @@ -80,15 +85,29 @@ internal IEdmModel ServiceModel
{
get
{
if (serviceModel == null && LoadServiceModel != null)
if (serviceModel != null)
{
serviceModel = LoadServiceModel();
return serviceModel;
}

if (LoadServiceModel != null)
{
serviceModel = LoadServiceModel();
}
else
{
serviceModel = LoadServiceModelFromNetwork();
}
return serviceModel;
}
}

/// <summary>
/// Invoked during test cases to fake out network calls to get the metadata
/// returns a string that is passed to the csdl parser and is used to bypass the network call while testing
/// </summary>
internal Func<HttpWebRequestMessage> InjectMetadataHttpNetworkRequest { get; set; }

/// <summary>
/// Indicates that the client should use the efficient JSON format.
/// </summary>
Expand Down Expand Up @@ -274,5 +293,78 @@ private static string ChooseMediaType(bool hasSelectQueryOption)

return MimeApplicationJsonODataLight;
}

/// <summary>
/// Loads the metadata and converts it into an EdmModel that is then used by a dataservice context
/// This allows the user to use the DataServiceContext directly without having to manually pass an IEdmModel in the Format
/// </summary>
/// <returns>A service model to be used in format tracking</returns>
internal IEdmModel LoadServiceModelFromNetwork()
{
HttpWebRequestMessage httpRequest;
BuildingRequestEventArgs requestEventArgs = null;
// test hook for injecting a network request to use instead of the default
if (InjectMetadataHttpNetworkRequest != null)
{
httpRequest = InjectMetadataHttpNetworkRequest();
}
else
{
requestEventArgs = new BuildingRequestEventArgs(
"GET",
context.GetMetadataUri(),
null,
null,
context.HttpStack);

// fire the right events if they exist to allow user to modify the request
if (context.HasBuildingRequestEventHandlers)
{
requestEventArgs = context.CreateRequestArgsAndFireBuildingRequest(
requestEventArgs.Method,
requestEventArgs.RequestUri,
requestEventArgs.HeaderCollection,
requestEventArgs.ClientHttpStack,
requestEventArgs.Descriptor);
}

DataServiceClientRequestMessageArgs args = new DataServiceClientRequestMessageArgs(
requestEventArgs.Method,
requestEventArgs.RequestUri,
context.UseDefaultCredentials,
context.UsePostTunneling,
requestEventArgs.Headers);

httpRequest = new HttpWebRequestMessage(args);
}

Descriptor descriptor = requestEventArgs != null ? requestEventArgs.Descriptor : null;

// fire the right events if they exist
if (context.HasSendingRequest2EventHandlers)
{
SendingRequest2EventArgs eventArgs = new SendingRequest2EventArgs(
httpRequest,
descriptor,
false);

context.FireSendingRequest2(eventArgs);
}

Task<IODataResponseMessage> asyncResponse =
Task<IODataResponseMessage>.Factory.FromAsync(httpRequest.BeginGetResponse, httpRequest.EndGetResponse,
httpRequest);
IODataResponseMessage response = asyncResponse.GetAwaiter().GetResult();

ReceivingResponseEventArgs responseEvent = new ReceivingResponseEventArgs(response, descriptor);

context.FireReceivingResponseEvent(responseEvent);

using (StreamReader streamReader = new StreamReader(response.GetStream()))
using (XmlReader xmlReader = XmlReader.Create(streamReader))
{
return CsdlReader.Parse(xmlReader);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\..\..\sln\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\..\..\sln\packages\System.Threading.Tasks.Extensions.4.5.1\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.XML" />
<Reference Include="System.Xml.Linq" />
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
Expand Down Expand Up @@ -461,6 +470,10 @@
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.OData.Client\Microsoft.OData.Client.csproj">
<Project>{D1567C63-4A0D-4E18-A14E-79699B9BFFFF}</Project>
<Name>Microsoft.OData.Client</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\src\Microsoft.OData.Core\Microsoft.OData.Core.csproj">
<Project>{989a83cc-b864-4a75-8bf3-5eda99203a86}</Project>
<Name>Microsoft.OData.Core</Name>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.0" targetFramework="net451" />
<package id="xunit" version="2.1.0" targetFramework="net45" />
<package id="xunit.abstractions" version="2.0.0" targetFramework="net45" />
<package id="xunit.assert" version="2.1.0" targetFramework="net45" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.OData.Client.TDDUnitTests.Tests;

namespace Microsoft.OData.Client.TDDUnitTests
{
public static class DataServiceContextUtil
{
private const string ValidEdmx = @"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""Test"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityContainer Name=""Container"" />
</Schema>
</edmx:DataServices>
</edmx:Edmx>";

public static DataServiceContext ReConfigureForNetworkLoadingTests(this DataServiceContext context)
{
context.Format.InjectMetadataHttpNetworkRequest = InjectFakeEdmxRequest;
return context;
}
internal static HttpWebRequestMessage InjectFakeEdmxRequest()
{
return new CustomizedHttpWebRequestMessage(
new DataServiceClientRequestMessageArgs(
"GET",
new Uri("http://temp.org/"),
false,
false,
new Dictionary<string, string>()),
ValidEdmx,
new Dictionary<string, string>());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
<Compile Include="..\ClientExtensions\TestDataServiceClientRequestMessage.cs">
<Link>TestDataServiceClientRequestMessage.cs</Link>
</Compile>
<Compile Include="DataServiceContextUtil.cs" />
<Compile Include="DateTimePrimitiveTypeReference.cs" />
<Compile Include="Tests\Annotation\AnnotationTargetingOperationTestsProxy.cs" />
<Compile Include="Tests\Annotation\ClientAnnotationTests.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ public class ClientPropertyTrackingTests
[TestInitialize]
public void Init()
{
this.context = new DataServiceContext(new Uri("http://www.odata.org/service.svc"));
this.context = new DataServiceContext(new Uri("http://www.odata.org/service.svc")).ReConfigureForNetworkLoadingTests();
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,28 @@ namespace AstoriaUnitTests.TDD.Tests.Client
using System.IO;
using System.Linq;
using System.Xml;
using FluentAssertions;
using Microsoft.OData.Client;
using Microsoft.OData.Client.Metadata;
using FluentAssertions;
using Microsoft.OData;
using Microsoft.OData.Edm;
using Microsoft.Spatial;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.OData.Client.TDDUnitTests;

/// <summary>
/// Unit tests for client request serialization code.
/// </summary>
[TestClass]
public class ClientSerializerTests
{
private DataServiceContext context;

[TestInitialize]
public void Init()
{
context = new DataServiceContext(new Uri("http://www.odata.org/service.svc")) { ResolveName = type => type.FullName }.ReConfigureForNetworkLoadingTests();
}
[TestMethod]
public void ClientShouldNotIncludeIdInJsonLightUpdates()
{
Expand Down Expand Up @@ -108,7 +116,6 @@ private abstract class MyMleType
[TestMethod]
public void WriteNullUriOperationParametersToUriShouldReturnUri()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc"));
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
Uri requestUri = new Uri("http://www.odata.org/service.svc/Function");
Expand All @@ -120,7 +127,6 @@ public void WriteNullUriOperationParametersToUriShouldReturnUri()
[TestMethod]
public void WriteOneUriOperationParametersToUriShouldReturnUri()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc"));
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
Uri requestUri = new Uri("http://www.odata.org/service.svc/Function");
Expand All @@ -133,7 +139,6 @@ public void WriteOneUriOperationParametersToUriShouldReturnUri()
[TestMethod]
public void WriteTwoUriOperationParametersToUriShouldReturnUri()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc"));
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
Uri requestUri = new Uri("http://www.odata.org/service.svc/Function");
Expand All @@ -147,7 +152,6 @@ public void WriteTwoUriOperationParametersToUriShouldReturnUri()
[TestMethod]
public void WriteStringAndBoolUriOperationParametersToUriShouldReturnUri()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc"));
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
Uri requestUri = new Uri("http://www.odata.org/service.svc/Function");
Expand All @@ -161,7 +165,6 @@ public void WriteStringAndBoolUriOperationParametersToUriShouldReturnUri()
[TestMethod]
public void WritePrimitiveUriOperationParametersToUriShouldReturnUri()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc"));
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
Uri requestUri = new Uri("http://www.odata.org/service.svc/Function");
Expand All @@ -178,7 +181,6 @@ public void WritePrimitiveUriOperationParametersToUriShouldReturnUri()
[TestMethod]
public void WriteDateAndTimeUriOperationParametersToUriShouldReturnUri()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc"));
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
Uri requestUri = new Uri("http://www.odata.org/service.svc/Function");
Expand All @@ -194,7 +196,6 @@ public void WriteDateAndTimeUriOperationParametersToUriShouldReturnUri()
[TestMethod]
public void WriteGeographyUriOperationParametersToUriShouldReturnUri()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc"));
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
Uri requestUri = new Uri("http://www.odata.org/service.svc/Function");
Expand All @@ -209,7 +210,6 @@ public void WriteGeographyUriOperationParametersToUriShouldReturnUri()
[TestMethod]
public void WriteCollectionUriOperationParametersToUriShouldReturnUri()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc"));
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
Uri requestUri = new Uri("http://www.odata.org/service.svc/Function");
Expand All @@ -224,7 +224,6 @@ public void WriteCollectionUriOperationParametersToUriShouldReturnUri()
[TestMethod]
public void WriteEnumUriOperationParametersToUriShouldReturnUri()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc"));
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
Uri functionBaseRequestUri = new Uri("http://www.odata.org/service.svc/Function");
Expand All @@ -246,7 +245,6 @@ public void WriteEnumUriOperationParametersToUriShouldReturnUri()
[TestMethod]
public void WriteComplexTypeUriOperationParametersToUriShouldReturnUri()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc")) { ResolveName = type => type.FullName };
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
Uri requestUri = new Uri("http://www.odata.org/service.svc/Function");
Expand All @@ -261,7 +259,6 @@ public void WriteComplexTypeUriOperationParametersToUriShouldReturnUri()
[TestMethod]
public void WriteCollectionOfComplexTypeInUri()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc")) { ResolveName = type => type.FullName };
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
Uri requestUri = new Uri("http://www.odata.org/service.svc/Function");
Expand All @@ -281,7 +278,6 @@ public void WriteCollectionOfComplexTypeInUri()
[TestMethod]
public void WriteCollectionOfComplexTypeInBody()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc")) { ResolveName = type => type.FullName };
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
List<Address> addresses = new List<Address>()
Expand All @@ -300,7 +296,6 @@ public void WriteCollectionOfComplexTypeInBody()
[TestMethod]
public void WriteEntryAsBodyOperationParameter()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc")) { ResolveName = type => type.FullName };
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
Customer customer = new Customer()
Expand All @@ -320,7 +315,6 @@ public void WriteEntryAsBodyOperationParameter()
[TestMethod]
public void WriteNullAsBodyOperationParameter()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc")) { ResolveName = type => type.FullName };
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
List<BodyOperationParameter> parameters = new List<BodyOperationParameter> { new BodyOperationParameter("customer", null) };
Expand All @@ -333,7 +327,6 @@ public void WriteNullAsBodyOperationParameter()
[TestMethod]
public void WriteFeedAsBodyOperationParameter()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc")) { ResolveName = type => type.FullName };
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
Customer customer1 = new Customer()
Expand All @@ -359,7 +352,6 @@ public void WriteFeedAsBodyOperationParameter()
[TestMethod]
public void WriteEmptyFeedAsBodyOperationParameter()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc")) { ResolveName = type => type.FullName };
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
List<BodyOperationParameter> parameters = new List<BodyOperationParameter> { new BodyOperationParameter("customer", new List<Customer>()) };
Expand Down Expand Up @@ -389,7 +381,6 @@ private void VerifyMessageBody(ODataRequestMessageWrapper requestMessage, string
[TestMethod]
public void WriteEnumTypeUriOperationParameterWithNonExistingValueShouldThrow()
{
DataServiceContext context = new DataServiceContext(new Uri("http://www.odata.org/service.svc"));
var requestInfo = new RequestInfo(context);
var serializer = new Serializer(requestInfo);
Uri requestUri = new Uri("http://www.odata.org/service.svc/Function");
Expand Down
Loading