我有一个从实体框架返回数据的 WCF 服务。它返回的对象是一个 ShippingLine,它是 OrderLine 的子代,OrderLine 是订单的子代。
在我的 WCF 服务中,我有以下代码:
var shippingLine = _dbContext.ShippingLines
.Include(l => l.OrderLine)
.Include(l => l.OrderLine.Order)
.Include(l => l.OrderLine.Order.Customer)
.Include(l => l.OrderLine.Order.Customer.CustomerAddress)
.Include(l => l.OrderLine.Order.Customer.CustomerAddress.Country)
.Include(l => l.OrderLine.Order.Customer.CustomerAddress.State)
.Include(l => l.OrderLine.OrderLineOptions)
.Include(l => l.OrderLine.OrderLineOptions.First().Option)
.Include(l => l.OrderLine.OrderLineOptions.First().Option.ExternalPrintingSystemMapping)
.Include(l => l.OrderLine.OrderLineStatus)
.Include(l => l.TrackingNumbers)
.Include(l => l.ShippingMethod)
.Include(l => l.ShippingMethod.ShippingRates)
.Include(l => l.ShippingBox)
.Include(l => l.BulkMailingAsset)
.Include(l => l.BulkPostageType)
.FirstOrDefault<ShippingLine>(line => line.Id == id);
我们正在使用一些围绕 EF 和自跟踪实体的自定义扩展方法来帮助我们编写单元测试。我们已经实现了我们自己的 Include 方法,这些方法在上面被调用:
public static IQueryable<TSource> Include<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, object>> exp) where TSource : class
{
var objectQuery = source as ObjectQuery<TSource>;
if (objectQuery != null)
{
return objectQuery.Include(ObjectQueryExtensionMethods.GetIncludePath((MemberExpression)exp.Body));
}
var fakeObjectSet = source as FakeObjectSet<TSource>;
if (fakeObjectSet != null)
{
fakeObjectSet.Include(exp);
}
return source;
}
public static IQueryable<TSource> Include<TSource>(this IQueryable<TSource> source, string path) where TSource : class
{
var objectQuery = source as ObjectQuery<TSource>;
if (objectQuery != null)
{
return objectQuery.Include(path);
}
var fakeObjectSet = source as FakeObjectSet<TSource>;
if (fakeObjectSet != null)
{
fakeObjectSet.Include(path);
}
return source;
}
最上面的方法是我目前正在使用的方法。我试过使用第二个,它采用像“Orderline.Order.Customer”这样的字符串页面,而行为没有改变。最上面的 Include 方法就是使用这个方法来获取包含路径:
internal static string GetIncludePath(MemberExpression memberExpression)
{
string path = "";
if (memberExpression.Expression is MethodCallExpression)
path = GetIncludePath((MemberExpression)((memberExpression.Expression as MethodCallExpression).Arguments[0])) + ".";
if (memberExpression.Expression is MemberExpression)
path = GetIncludePath((MemberExpression)memberExpression.Expression) + ".";
return path + memberExpression.Member.Name;
}
然后我将此运输线返回给 MVC 控制器,然后该控制器尝试访问 OrderLine 对象上的 Order。出于某种原因,尽管 OrderLine 对象上的每个属性都为 null 或设置为其默认值。所以我无法在下面的代码中访问 Order 对象,因为 Order 为空:
line.OrderLine.Order.Customer.CustomerAddress;
我正在使用 4.0 框架和 EF 4 自跟踪实体。
我确定它包含 OrderLine 和 Order 信息,因为在调试器中我可以在 OrderLine 和 Order 返回给客户端之前正确地看到它。
但是,当它到达客户端时,所有 OrderLine 属性都为 null 或默认值,并且 Order 不存在。所有其他包括似乎工作正常。
关系是 Order(一)到 OrderLine(多),OrderLine(一)到 ShippingLine(多)。
到目前为止我已经尝试过...... 1. 在客户端更新我的服务参考。2. 在客户端删除并重新创建我的服务引用。3. 在客户端上打开详细的 WCF 跟踪。我在跟踪中没有看到任何问题。
知道为什么包含的对象会像这样被丢弃吗?
这是我的客户端 web.config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IMyService" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxBufferSize="2147483646" maxBufferPoolSize="2147483646" maxReceivedMessageSize="2147483646" messageEncoding="Mtom">
<readerQuotas maxDepth="256" maxStringContentLength="5242880" maxArrayLength="2147483646" maxBytesPerRead="4096" maxNameTableCharCount="2147483646" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/MyService/systemservice.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyService" contract="MyService.IMyService" name="BasicHttpBinding_IMyService" />
</client>
这是我的网络服务 web.config:
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
<services>
<service name="MyApi.MyService">
<endpoint behaviorConfiguration="MyServiceBehavior" binding="basicHttpBinding" bindingConfiguration="MyServiceBindingConfiguration"
contract="MyApi.IMyService"/>
<host>
<timeouts openTimeout="00:05:00"/>
</host>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="MyServiceBindingConfiguration" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"
maxBufferSize="2147483646" maxBufferPoolSize="2147483646" maxReceivedMessageSize="2147483646" messageEncoding="Mtom">
<readerQuotas maxDepth="256" maxStringContentLength="5242880" maxArrayLength="2147483646" maxBytesPerRead="4096" maxNameTableCharCount="5242880"/>
</binding>
<binding name="ServiceSoap" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<!-- productionProxyAddress https://api.authorize.net/soap/v1/Service.asmx -->
<endpoint address="https://apitest.authorize.net/soap/v1/Service.asmx" binding="basicHttpBinding" bindingConfiguration="ServiceSoap"
contract="AuthorizeNet.ServiceSoap" name="ServiceSoap"/>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="MyServiceBehavior">
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>