65.9K
CodeProject 正在变化。 阅读更多。
Home

在 Visual Studio 2015 中为 AngularJS 创建和使用简单的 WCF / RESTful 服务

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (7投票s)

2016年2月23日

GPL3

6分钟阅读

viewsIcon

58593

downloadIcon

1648

这是一个完整的端到端应用程序,可在 VS2015 IDE 中运行,使 WCF 能够将 JSON 传递给 AngularJS。

引言

这是一份端到端的描述,介绍如何在 Visual Studio 2015 中创建和搭建一个 WCF Restful 服务,该服务可以被 AngularJS 调用。

背景

我写这篇文章是因为我找不到一个独立的示例,可以在 Visual Studio 2015 中创建和运行一个简单但完整的 WCF/JSON/AngularJS 应用程序。

相反,我发现了一些很好的文章,它们分别解决了编写和使用 JSON、WCF 中的 REST、或 AngularJS 的各个方面。

因此,我根据其他几篇文章创建了这篇文章,并加入了我的经验,以使应用程序能够正常工作。凡是我摘录代码的地方,我都尽量注明了作者的 URL。

使用代码

这是一本菜谱。就像所有食谱一样,我只是提供一个可行的基础,以便您可以根据自己的需求对其进行修改。

使用 VS2015 创建 RESTful 服务

创建应用程序

打开 VS2015,新建一个项目,选择 WCF 服务应用程序。

我将我的项目命名为 RestSample,并将项目命名为 WcfRestfulService。

向项目中添加新的 WCF 服务

通过右键单击项目 WcfRestfulService,然后选择 WCF 服务,添加一个新的服务和接口。

我将服务命名为 *ProductService.svc*。另外,您可以删除现有的 IService 和 *Service.svc* 文件,因为我们不使用它们。

创建数据模型

此步骤是可选的,因为之后您可以简单地传递一个 JSON 字符串。不过,这展示了如何使用序列化从 .NET 类创建 JSON 格式的字符串,这是非常常见的。

要创建数据模型,首先创建一个文件夹(我称之为 Domain),用于托管我们的数据服务。您可以通过右键单击项目文件并选择添加新文件夹来完成此操作。

在文件夹中添加一个类,方法是右键单击文件夹,点击添加,选择添加类。

我将我的文件和类命名为 Product。下面是该类的内容,已准备好在 WCF 中进行序列化。

                    [DataContract]
                    public class Product
                    {
                        [DataMember]
                        public int ProductId { get; set; }
                        [DataMember]
                        public string Name { get; set; }
                        [DataMember]
                        public string CategoryName { get; set; }
                        [DataMember]
                        public int Price { get; set; }
                    }

接下来,我创建了一个名为 *ProductServer.cs* 的静态类,用于创建和提供产品列表。

                    public sealed class ProductsServer
                    {
                        private static List<Product> _products;
                        private static ProductsServer _instance;
                        private static readonly object LockMechanism = new object();
                        public static ProductsServer Instance
                        {
                            get
                            {
                                if (_instance == null)
                                {
                                    //not really neccessary on a small project, but it is the Microsoft recommended pattern
                                    lock (LockMechanism)
                                    {
                                        _instance = new ProductsServer();
                                    }
                                }
                                return _instance;
                            }
                        }
                        private ProductsServer()
                        {
                            Intialize();
                        }
                        private static void Intialize()
                        {
                            _products = new List<Product>
                                            {
                                                new Product() {ProductId = 1, Name = "Product 1", CategoryName = "Category 1", Price = 10},
                                                new Product() {ProductId = 2, Name = "Product 2", CategoryName = "Category 1", Price = 5},
                                                new Product() {ProductId = 3, Name = "Product 3", CategoryName = "Category 2", Price = 15},
                                                new Product() {ProductId = 4, Name = "Product 4", CategoryName = "Category 3", Price = 9}
                                            };
                        }
                        public List<Product> Products
                        {
                            get { return _products; }
                        }
                    }

使用 Web 协议修改 IProductService

IProductService 中,删除 DoWork 函数,并将其替换为 GetProductList

接下来添加 WebInvoke 装饰,以便基于 Java 的调用者(如 AngularJS 和 AJAX)可以读取我们 JSON 格式的产品列表。

                [ServiceContract]
                public interface IProductService
                {
                    [OperationContract]
                    [WebInvoke(Method = "GET",
                        ResponseFormat = WebMessageFormat.Json,
                        RequestFormat = WebMessageFormat.Json,
                        BodyStyle = WebMessageBodyStyle.Bare,
                        UriTemplate = "GetProductList/")]
                    List<Product> GetProductList();
                }

ProductService 类中添加对我们之前创建的 ProductServer 的引用,以获取列表。

                public class ProductService : IProductService
                {
                    List<Product> IProductService.GetProductList()
                    {
                        return ProductsServer.Instance.Products;
                    }
                }

正如 Ghani 先生可能已经注意到的,这与他的页面非常相似,事实上,我正以他的页面为指导。他的优秀文章可以在 TopWcfTutorials 找到

代码清理

此时,产品应该是一个完整的 WCF 服务;另一方面,我似乎总会遇到一些需要解决的问题。

要测试我们的工作,请右键单击 svc 文件,然后选择在浏览器中查看。

当我尝试这样做时,我收到了以下错误:

在 ServiceHost 指令中作为 Service 属性值提供的,或者在配置元素 system.serviceModel/serviceHostingEnvironment/serviceActivations 中提供的类型 'WcfService1.ProjectService' 未找到。

正如错误所示,我忘记更改命名空间,这是一个很容易犯的错误,因此我将其保留。

要解决此问题,请右键单击 *ProductService.svc*,选择查看标记,然后使用 XML(文本)编辑器打开。您会看到服务仍然标记为 WcfService1。请将其更改为 WcfRestulService。

在我进行此操作时,我回到了我的项目文件,并更改了默认的程序集名称和命名空间(右键单击项目文件。选择属性)。

现在我遇到了一个新的错误。

OperationContractAttributes 仅对声明在具有 ServiceContractAttribute 的类型中的方法有效。

查看 Web.config,我发现没有端点或行为,所以我们需要构建配置。

重构 Web.config,添加端点、服务和行为

在协议映射中添加 binding 类型为 webHttpBinding。

添加行为。

添加服务端点。

现在我们有了一个可用的服务。不幸的是,它是 SOAP 格式的,而我们想要 REST 格式,所以我们添加以下行为扩展。

接下来,我们需要在端点行为中引用该扩展。

最后,我们需要添加一个类来处理跨平台服务调用。这个类是从 CORS plus JSON Rest 复制的。

添加 CORS 扩展

右键单击项目,添加一个新文件以启用 CORS - 跨域资源共享。启用 CORS 将允许我们在浏览器中直接看到 JSON 字符串,并将允许 AngularJS 读取 RESTful 服务所需的权限。

        public class CORSEnablingBehavior : BehaviorExtensionElement, IEndpointBehavior
        {
            public void AddBindingParameters(
              ServiceEndpoint endpoint,
              BindingParameterCollection bindingParameters)
            { }
            public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { }
            public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
            {
                endpointDispatcher.DispatchRuntime.MessageInspectors.Add(
                  new CORSHeaderInjectingMessageInspector()
                );
            }
            public void Validate(ServiceEndpoint endpoint) { }
            public override Type BehaviorType { get { return typeof(CORSEnablingBehavior); } }
            protected override object CreateBehavior() { return new CORSEnablingBehavior(); }
            private class CORSHeaderInjectingMessageInspector : IDispatchMessageInspector
            {
                public object AfterReceiveRequest(
                  ref Message request,
                  IClientChannel channel,
                  InstanceContext instanceContext)
                {
                    return null;
                }
                private static IDictionary<string, string> _headersToInject = new Dictionary<string, string>
                  {
                    { "Access-Control-Allow-Origin", "*" },
                    { "Access-Control-Request-Method", "POST,GET,PUT,DELETE,OPTIONS" },
                    { "Access-Control-Allow-Headers", "X-Requested-With,Content-Type" }
                  };
                public void BeforeSendReply(ref Message reply, object correlationState)
                {
                    var httpHeader = reply.Properties["httpResponse"] as HttpResponseMessageProperty;
                    foreach (var item in _headersToInject)
                        httpHeader.Headers.Add(item.Key, item.Value);
                }
            }
        }

测试服务

此时,我们应该可以在浏览器中看到我们的产品列表已序列化为 JSON。您可以通过右键单击 *ProductService.svc*(像之前一样),并添加对服务 * /GetProductList* 的调用来做到这一点。

在我的浏览器中看起来是这样的:

创建 AngularJS 应用程序来消费服务

添加一个空的 ASP.Net Web 应用程序。

在解决方案文件上,右键单击并选择 Web,ASP.NET Web 应用程序。我将其命名为 WebApp。

接下来选择空模板,然后点击 OK。

通过右键单击项目文件添加 Index.html。

加载 AngularJS 库

如果您还没有 AngularLS 库文件,请打开程序包管理器控制台。您可以在“视图”->“其他窗口”->“程序包管理器控制台”下找到它。

通过在 PM> 提示符下键入以下命令,直接从 NuGet 加载 AngularJS 文件:

Install-Package AngularJS.Core

这会将 AngularJS 核心库添加到 scripts 文件夹。我不得不打开和关闭文件夹几次才能看到更改,但下面是加载库后 scripts 文件夹的图像。

创建 AngularJS 应用程序和模块文件

首先,在 WebApp 中创建一个名为 app 的文件夹。

我将按照推荐的通用做法将应用程序和模块文件分开。

通过右键单击 app 文件夹,选择添加,然后选择 JavaScript 文件,创建两个名为 app.module.js 和 main.js 的 JavaScript 文件。

将以下代码添加到 app.module。

            (function () {
                'use strict';
                angular.module('app', []);
            })();

将以下代码添加到 main。您需要修改 URL,使其使用与您的 WcfRestfulService 服务相同的端口。

            (function () {
                'use strict';
                angular
                    .module('app')
                    .controller('Main', main);
                function main($scope, $http) {
                    $http.get('https://:62243/ProductService.svc/GetProductList').then(function (response) {
                        $scope.products = response.data;
                    });
                }
            })();

您可以通过单击服务并查看“开发服务器”部分中的 URL 来找到端口号。在我的例子中是 62245。在每个计算机上都会不同。

要测试服务,您应该能够复制或单击 URL,像之前一样看到服务。

引用您的 AngularJS 文件

我们终于准备好将 WebApp 连接到服务了。为此,我们需要在 Index.html 中引用 js 类,以便它能找到 AngularJS 库和模块。

我们将构建的页面非常简单。同时,它完成了从头到尾的项目。

为了绑定到应用程序和控制器,我们需要在 body 中添加应用程序指令和控制器指令。

最后,我们需要创建一个表,并使用 repeat 指令将其绑定到我们的服务提供的 JSON 数据。

别忘了,像我一样,将 WebApp 设置为启动项目,方法是右键单击项目文件并选择“设置为启动项目”。

简单的结果如下所示:

历史

2016 年 2 月 22 日 - 提交

© . All rights reserved.