前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 ServiceStack 构建跨平台 Web 服务

使用 ServiceStack 构建跨平台 Web 服务

作者头像
张善友
发布2018-01-29 14:25:41
1.6K0
发布2018-01-29 14:25:41
举报
文章被收录于专栏:张善友的专栏张善友的专栏

本文主要来自MSDN杂志《Building Cross-Platform Web Services with ServiceStack》,Windows Communication Foundation (WCF) 是一个相当优秀的服务框架,当我们讨论跨平台的服务的时候,虽然WCF对WebService的支持还行,在面对一些高级应用的不太好,微软重新发展了ASP.NET WebAPI框架,关于这两个框架的讨论可以看我另外一篇文章《WCF和ASP.NET Web API在应用上的选择》 。在讨论跨平台的Web服务上,ASP.NET Web API是一个重要选项,在本文中,我将展示如何利用 ServiceStack (开放源代码.NET 和Mono REST 服务框架) 来完成这一任务,不用离开 Visual Studio 或 Microsoft.NET/Mono,除了 ServiceStack 之外还有个Nancy的框架,具体可以看《.NET的微型Web框架 Nancy》。

一个典型的 Web 服务结构如下:

Print
Print
  • 服务层是您定义您的Web 服务接口的地方。 这也是,客户端和你的 Web 服务进行交互的一层。
  • 业务层通常是业务逻辑
  • 数据层是为了封装数据访问和操纵在业务层提供抽象的数据模型。
  • Web服务通常有远程过程调用(RPC)和RESTful (HTTP)两类,现在占据主导地位的Web服务是RESTful (HTTP),具体内容可以参看文章《REST在企业中获得成功了么?》,贴一张文章里的图片:
REST&SOAP1
REST&SOAP1

2年前REST就已经成为Web API部署方式的主流了,而且一直保持这种发展势头,现在基本上都是REST服务,SOAP在企业内网还存在。

远程过程调用 (RPC) ,每个请求旨在类似于函数调用:

代码语言:js
复制
public interface IService
{
      string DoSomething(int input);
}

RPC 方法对服务的修改非常不友好。 例如前面的代码段,如果要求从客户端来执行更高版本的 Web 服务的 DoSomething 方法的两个输入参数 — 或需要返回字符串值之外的另一个字段 —— 给老客户重大更改是不可避免的。 当然,您始终可以创建平行的 DoSomething_v2 方法,要带两个输入的参数,但久而久之会搞乱您的 Web 服务接口和消费者,服务变得越来越丑,用WCF实现的Web服务就是属于这种情况,下面我们介绍ServiceStack。

ServiceStack是.Net和Mono的开源框架,相对WCF,MVC及Web API而言它是开发Web服务与Web应用的有力替代品,它越来越普及。 用 ServiceStack 生成的 web 服务可以运行在 Windows 环境中,.NET 代码或Mono支持 Linux 环境中。 Mono支持的操作系统包括:

  • Linux
  • Mac OS X, iOS
  • Sun Solaris
  • BSD
  • Microsoft Windows
  • Nintendo Wii
  • Sony PlayStation 3

ServiceStack是一系列事物的综合体:

ServiceStack 强制远程 Web 服务最佳实践、 基于公约 DTO 标准为其 Web 服务接口,ServiceStack 还提供预置的响应状态对象,可用于撰写 DTO,鼓励更加直接和简单的错误处理方案,显然和WCF是明显不同的路线。

本文假定您有一些熟悉 WCF 和.NET 框架。 为了更好地展示WCF 概念可以如何转化为 ServiceStack 的概念,首先会在WCF中实现服务层。我会告诉你如何通过将WCF Web 服务移植到等效的使用 ServiceStack 转换为跨平台的 Web 服务。

WCF 使用数据合同建立的客户端和服务器之间的通信手段。 ServiceStack和WCF相同。 WCF 需要何数据对象和数据成员打上标记; 否则,WCF 简单地忽略它们。 这是 ServiceStack 和 WCF 与的不同的地方。 ServiceStack 支持所有POCO 的对象作为契约:

WCF的契约:

代码语言:js
复制
   [DataContract] 
    public class Ticket     
    {     
        [DataMember]     
        public int TicketId { get; set; }     
        [DataMember]     
        public int TableNumber { get; set; }     
        [DataMember]     
        public int ServerId { get; set; }     
        [DataMember]     
        public List<Order> Orders { get; set; }     
        [DataMember]     
        public DateTime Timestamp { get; set; }     
    }     
    [ServiceContract]     
    public interface ITicketService     
    {     
        /// <summary>     
        /// 检索当前队列中的所有门票的完整清单     
        /// </summary>     
        /// <returns></returns>     
        [OperationContract]     
        List<Ticket> GetAllTicketsInQueue();
        /// <summary>    
        /// 新增新门票     
        /// </summary>     
        /// <param name="ticket"></param>     
        [OperationContract]     
        void QueueTicket(Ticket ticket);
        /// <summary>    
        /// 从队列拉出一张票     
        /// </summary>     
        /// <returns></returns>     
        [OperationContract]     
        Ticket PullTicket();     
    }     
}

把它转换为ServiceStack的契约:

代码语言:js
复制
public class Ticket    
{     
       public int TicketId { get; set; }     
        public int TableNumber { get; set; }     
        public int ServerId { get; set; }     
        public List<Order> Orders { get; set; }     
        public DateTime Timestamp { get; set; }
}
public class GetAllTicketsInQueueRequest    
{     
}
public class QueueTicketRequest    
{     
    public Ticket Ticket { get; set; }     
}
public class PullTicketRequest    
{     
}
public interface ISCTicketService    
{     
    List<Ticket> Any(GetAllTicketsInQueueRequest request);
    void Any(QueueTicketRequest request);
    Ticket Any(PullTicketRequest request);    
}

ServiceStack 规定每个唯一的请求是对象所标识唯一的请求,这意味着你不能重用 DTO 跨多个服务实现与 ServiceStack 的请求。ServiceStack 支持不同的操作,如有 Get 和 Post。 您的选择在这里仅影响的 HTTP 请求。 指定任何 Web 服务请求是指可以通过 HTTP GET 和 HTTP POST 调用操作。 这种强制措施,简化了 rest 风格的 Web 服务实现。要将您的 ServiceStack Web 服务变成 rest 风格的 Web 服务,只需添加 URL [Route(...)]向您的 Web 服务请求声明属性。

代码语言:js
复制
    //Request DTO    
    public class Hello     
    {     
        public string Name { get; set; }     
    }
    //Response DTO    
    public class HelloResponse     
    {     
        public string Result { get; set; }     
        public ResponseStatus ResponseStatus { get; set; } //Where Exceptions get auto-serialized     
    }
    //Can be called via any endpoint or format, see: http://servicestack.net/ServiceStack.Hello/ 
    public class HelloService : Service     
    {     
        public object Any(Hello request)     
        {     
            return new HelloResponse { Result = "Hello, " + request.Name };     
        }     
    }
    //REST Resource DTO    
    [Route("/todos")]     
    [Route("/todos/{Ids}")]     
    public class Todos : IReturn<List<Todo>>     
    {     
        public long[] Ids { get; set; }     
        public Todos(params long[] ids)     
        {     
            this.Ids = ids;     
        }     
    }
    [Route("/todos", "POST")]    
    [Route("/todos/{Id}", "PUT")]     
    public class Todo : IReturn<Todo>     
    {     
        public long Id { get; set; }     
        public string Content { get; set; }     
        public int Order { get; set; }     
        public bool Done { get; set; }     
    }
    public class TodosService : Service    
    {     
        public TodoRepository Repository { get; set; }  //Injected by IOC
        public object Get(Todos request)    
        {     
            return request.Ids.IsEmpty()     
                ? Repository.GetAll()     
                : Repository.GetByIds(request.Ids);     
        }
        public object Post(Todo todo)    
        {     
            return Repository.Store(todo);     
        }
        public object Put(Todo todo)    
        {     
            return Repository.Store(todo);     
        }
        public void Delete(Todos request)    
        {     
            Repository.DeleteByIds(request.Ids);     
        }     
    }    

以ASP.NET Hosting承载ServiceStack,创建一个空的ASP.NET应用,使用 NuGet 包管理器控制台将 ServiceStack 引用添加到 ServiceStack.Host.AspNet中所示

image
image

Web.config 会增加下面的配置

代码语言:js
复制
<configuration>    
  <system.web>     
    <compilation debug="true" targetFramework="4.0" />     
   <httpHandlers>      
      <add path="*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" />       
    </httpHandlers>       
  </system.web>     
  <system.webServer>     
    <modules runAllManagedModulesForAllRequests="true" />     
    <validation validateIntegratedModeConfiguration="false" />     
   <handlers>      
      <add path="*" name="ServiceStack.Factory" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true" />       
    </handlers> 
  </system.webServer>     
</configuration>

你需要从 ServiceStack.WebHost.End 继承­实现端点。

代码语言:js
复制
public class AppHost  : AppHostBase    
    {        
        public AppHost() //Tell ServiceStack the name and where to find your web services     
            : base("StarterTemplate ASP.NET Host", typeof(HelloService).Assembly) { }
        public override void Configure(Funq.Container container)    
        {     
            //Set JSON web services to return idiomatic JSON camelCase properties     
            ServiceStack.Text.JsConfig.EmitCamelCaseNames = true;     
 
            //Configure User Defined REST Paths     
            Routes     
              .Add<Hello>("/hello")     
              .Add<Hello>("/hello/{Name*}");
            //Uncomment to change the default ServiceStack configuration    
            //SetConfig(new EndpointHostConfig {     
            //});
            //Enable Authentication    
            //ConfigureAuth(container);
            //Register all your dependencies    
            container.Register(new TodoRepository());            
        }
        /* Uncomment to enable ServiceStack Authentication and CustomUserSession    
        private void ConfigureAuth(Funq.Container container)     
        {     
            var appSettings = new AppSettings();
            //Default route: /auth/{provider}    
            Plugins.Add(new AuthFeature(() => new CustomUserSession(),     
                new IAuthProvider[] {     
                    new CredentialsAuthProvider(appSettings),     
                    new FacebookAuthProvider(appSettings),     
                    new TwitterAuthProvider(appSettings),     
                    new BasicAuthProvider(appSettings),     
                })); 
            //Default route: /register    
            Plugins.Add(new RegistrationFeature()); 
            //Requires ConnectionString configured in Web.Config    
            var connectionString = ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString;     
            container.Register<IDbConnectionFactory>(c =>     
                new OrmLiteConnectionFactory(connectionString, SqlServerDialect.Provider));
            container.Register<IUserAuthRepository>(c =>    
                new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>()));
            var authRepo = (OrmLiteAuthRepository)container.Resolve<IUserAuthRepository>();    
            authRepo.CreateMissingTables();     
        }     
        */
        public static void Start()    
        {     
            new AppHost().Init();     
        }     
    }

ServiceStack Web 应用程序启动时,您的服务合同列出作为元数据操作,如图所示:

image
image

相关文章:

SignalR, Filters and ServiceStack

采访ServiceStack的项目领导Demis Bellot——第1部分

采访ServiceStack的项目领导Demis Bellot——第2部分   

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2013-10-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档