OData 与 .NET 和 Java 的互操作性
OData 与 .NET C# 和 Java 应用程序的互操作性
引言
有时,为特定问题选择合适的技术并非易事。本文提供了一个在 .NET C# 和 Java 应用程序同时运行的环境中进行 OData 技术选择的决策过程。它还提供了如何在 .NET C# 中创建 OData RESTful 服务的代码示例,以及在 Java 应用程序中消费该服务的示例代码。OData 在这些 .NET 和 Java 应用程序中的互操作性看起来很不错。
背景
我们需要在数据中心 A 的 .NET C# 应用程序中从 Oracle 数据库检索大量数据并将其序列化为 JSON 格式,以便数据中心 B 的 Java 应用程序可以消费这些 JSON 数据。技术选择决策过程分为两步。
第 1 步:我们是在 .NET 应用程序中使用带 OData 的 Web API 还是使用 JSON.NET 的 WCF RESTful 服务?
经过在线研究,我们决定使用带 OData 的 Web API,基于以下 OData 优势。
- 一个开放协议,允许以简单和标准的方式创建和消费可查询和可互操作的 RESTful API。
- 微软于 2007 年发起 OData。OData v4 已在 OASIS 标准化。
- 可与 .NET、Java、PHP、iPhone、Android 等互操作。
- 是一个 OASIS 标准,定义了构建和消费 RESTful API 的最佳实践。
- 帮助您专注于业务逻辑,而无需担心请求/响应头、HTTP 方法、媒体类型、负载格式和查询选项等。
- 指导您跟踪更改、为可重用过程定义函数/动作以及发送异步/批量请求等。
- 提供扩展功能以满足 RESTful API 的任何自定义需求。
第 2 步:我们在 Java 应用程序中使用 odata4j 还是 Apache Olingo 库?
经过在线研究,我们决定在 Java 应用程序中使用 Olingo 库,原因如下。
- odata4j 库将不支持 OData v4。
- Apache Olingo 服务于 OData 的客户端和服务器端。它目前支持 OData 2.0,并将支持 OData 4.0。后者是该协议的 OASIS 版本:OASIS 开放数据协议 (OData) TC。
下一个问题是:如何在 .NET C# 和 Java 应用程序中使其工作?
.NET C# 端的工具和包如下:
- 带有 ASP.NET 5 的 Visual Studio 2015
- 最新的 Microsoft.AspNet.Odata(例如 OData 5.9.0)
- 最新的 EntityFramework(例如 EF 6.1.3)
Java 端的工具和包如下:
- Eclipse Kepler(非最新版本,因为 Olingo 库在 Juno 和 Kepler 上测试过)
- Apache Olingo 库 4.2
- Maven 3.2.1
在 .NET C# 端使用代码
http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api 上有很多很棒的 OData 教程。但是,如果您不使用 Visual Studio 2012 或 2013,示例代码可能无法工作。我将在这里重点介绍这些步骤,如果您使用的是 Visual Studio 2015,我将在第 4 步中明确提及配置更改。以防万一,我还会附上完整的示例代码。
第 1 步:创建新的 Visual Studio 项目
在 Visual Studio 中,从“文件”菜单中,选择“新建”>“项目”。
展开“已安装”>“模板”>“Visual C#”>“Web”,然后选择“ASP.NET Web 应用程序”模板。将项目命名为“ODataPartService”。
在“新建项目”对话框中,选择“空”模板。在“添加文件夹和核心引用...”下,单击“Web API”。
第 2 步:安装 OData 包
从“工具”菜单中,选择“NuGet 包管理器”>“包管理器控制台”。在“包管理器控制台”窗口中,键入
Install-Package Microsoft.AspNet.Odata
第 3 步:添加模型类
在解决方案资源管理器中,右键单击“Models”文件夹。从上下文菜单中,选择“添加”>“类”。将类命名为 Product。这是 Product.cs 文件中的示例代码,
namespace ProductService.Models
{
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
}
}
第 4 步:启用 Entity Framework
从“工具”菜单中,选择“NuGet 包管理器”>“包管理器控制台”。在“包管理器控制台”窗口中,键入
Install-Package EntityFramework
打开 Web.config 文件,并在 configuration
元素内,在 configSections
元素之后,添加一个 connectionStrings 元素。注意:数据源不是 (localdb)\V11.0,而是 locadb\MSSQLLocalDB。
<connectionStrings><add name="ProductsContext" connectionString="Data Source=(localdb)\MSSQLLocalDB;
Initial Catalog=ProductsContext; Integrated Security=True; MultipleActiveResultSets=True;
AttachDbFilename=|DataDirectory|ProductsContext.mdf"
providerName="System.Data.SqlClient" /> </connectionStrings>
接下来,在 Models 文件夹中添加一个名为 ProductsContext
的类。
public class ProductsContext : DbContext
{
public ProductsContext()
: base("name=ProductsContext")
{
}
public DbSet<Product> Products { get; set; }
}
第 5 步:配置 OData 终结点
将以下代码添加到 Register
方法中。
public static void Register(HttpConfiguration config)
{
// New code:
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: null,
model: builder.GetEdmModel());
}
第 6 步:添加 OData 控制器并查询实体集
在解决方案资源管理器中,右键单击“Controllers”文件夹,然后选择“添加”>“类”。将类命名为 ProductsController。
public class ProductsController : ODataController
{
ProductsContext db = new ProductsContext();
private bool ProductExists(int key)
{
return db.Products.Any(p => p.Id == key);
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
查询实体集。更多方法可以在 OData 教程和随附的代码中找到。
[EnableQuery]
public IQueryable<Product> Get()
{
return db.Products;
}
[EnableQuery]
public SingleResult<Product> Get([FromODataUri] int key)
{
IQueryable<Product> result = db.Products.Where(p => p.Id == key);
return SingleResult.Create(result);
}
第 7 步:添加 .NET C# 客户端以消费 OData 服务
遵循 http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/create-an-odata-v4-client-app 上的教程,或者直接使用随附的代码构建一个 C# 客户端来消费已创建的 OData v4 服务。注意:如果您使用 Visual Studio 2015,代码生成后没有名为 ProductClient.odata.config 的文件。相反,OData 服务 URL 需要在 ProductClient.tt 文件中修改。这是示例代码。
public static class Configuration
{
public const string MetadataDocumentUri = "https://:38173/";
public const bool UseDataServiceCollection = true;
public const string NamespacePrefix = "ProductsApp";
public const string TargetLanguage = "CSharp";
public const bool EnableNamingAlias = true;
public const bool IgnoreUnexpectedElementsAndAttributes = true;
}
在 Java 端使用代码
https://olingo.apache.org/doc/odata4/index.html 上有很多很棒的 Olingo 教程。
但是,如果您的计算机位于代理服务器后面和/或您的计算机存在任何其他未知问题,该说明可能不适用于您。当我尝试使用 Java 客户端消费在 .NET C# 中创建的 OData 服务时,我遇到了以下问题。
问题 1:使用 Maven 3.2 时的代理问题
通过在 settings.xml 配置的 proxies 元素内添加一个 proxy 元素,问题可以解决,如下所示。注意:settings.xml 文件可能不在 Maven 用户默认文件夹 c:\Users\xxxx\.m2 目录下。相反,它可能位于 Maven 安装文件夹中。例如 C:\apache-maven-3.2.1\conf 目录。请确保修改正确的 settings.xml 配置文件。
<proxy>
<id>optional</id>
<active>true</active>
<protocol>http</protocol>
<username>username</username>
<password>password</password>
<host>roxy.yourdomain</host>
<port>80</port>
<nonProxyHosts>maven.org|apache.org</nonProxyHosts>
</proxy>
问题 #2:导入 Olingo Maven 示例项目时出现 Maven 错误。错误如下。
https://codeproject.org.cn/KB/webservices/1093859/ODataJavaError1.JPG
可以通过首先禁用 Maven nature 来解决此问题。
https://codeproject.org.cn/KB/webservices/1093859/ODataJavaError2.JPG
然后将项目转换回 Maven 项目。
https://codeproject.org.cn/KB/webservices/1093859/ODataJavaError3.JPG
问题 #3:快速入门指南适用于 OData v2,不适用于 v4。
如果您正在使用本文中解释的最新 OData v4,请务必选择正确的客户端示例开始。最好使用 Olingo 源代码下载包中的客户端示例。这里有一些示例代码来消费在 .NET C# 中创建的 OData v4 服务。它也应该适用于 Java 服务,因为 Olingo 库中的示例客户端使用 Java 服务作为测试服务。
public class OlingoSampleApp {
private ODataClient client;
public OlingoSampleApp() {
client = ODataClientFactory.getClient();
}
public static void main(String[] params) throws Exception {
OlingoSampleApp app = new OlingoSampleApp();
app.perform("<a href="https://:38173/">https://:38173/</a>");
}
void perform(String serviceUrl) throws Exception {
Edm edm = readEdm(serviceUrl);
List<FullQualifiedName> ctFqns = new ArrayList<FullQualifiedName>();
List<FullQualifiedName> etFqns = new ArrayList<FullQualifiedName>();
for (EdmSchema schema : edm.getSchemas()) {
for (EdmComplexType complexType : schema.getComplexTypes()) {
ctFqns.add(complexType.getFullQualifiedName());
}
for (EdmEntityType entityType : schema.getEntityTypes()) {
etFqns.add(entityType.getFullQualifiedName());
}
}
public Edm readEdm(String serviceUrl) throws IOException {
EdmMetadataRequest request = client.getRetrieveRequestFactory().getMetadataRequest(serviceUrl);
ODataRetrieveResponse<Edm> response = request.execute();
return response.getBody();
}
}
.NET OData v4 服务:https://codeproject.org.cn/KB/webservices/1093859/ProductService.zip
.NET OData 客户端:https://codeproject.org.cn/KB/webservices/1093859/ProductsApp.zip
Java 客户端:https://codeproject.org.cn/KB/webservices/1093859/OlingoSampleApp.zip
参考文献
- 维基百科,2015,开放数据协议,https://en.wikipedia.org/wiki/Open_Data_Protocol
- OData 团队,2015,OData – REST 的最佳方式;http://www.odata.org/
- JC Cimetiere,2010,OData 与 .NET、Java、PHP、iPhone 等的互操作性;https://blogs.msdn.microsoft.com/interoperability/2010/03/16/odata-interoperability-with-net-java-php-iphone-and-more/
- Mike Wasson,2014,OData,http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api
- Apache Olingo 团队,2015,如何使用 Apache Olingo 作为客户端库,https://olingo.apache.org/doc/odata2/tutorials/OlingoV2BasicClientSample.html
- Apache Olingo 团队,2015,文档 Odata 4.0 Java 库,https://olingo.apache.org/doc/odata4/index.html
- Odata4j 团队,2015,odata4j,https://code.google.com/archive/p/odata4j/
- Yi Ding,2014,odata4j 对 OData 4.0 版本的支持,http://stackoverflow.com/questions/23333413/odata4j-support-for-odata-version-4-0
关注点
在这里写一篇文章很有趣。如果成员可以上传现有文档,那就太好了。
历史
初次发布