zoukankan      html  css  js  c++  java
  • 使用 ServiceStack 构建跨平台 Web 服务

    使用 ServiceStack 构建跨平台 Web 服务

    本文主要来自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

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

    REST&SOAP1

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

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

    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的契约:

       [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的契约:

    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 服务请求声明属性。

        //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

    Web.config 会增加下面的配置

    <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 继承­实现端点。

    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

    相关文章:

    Interview With Demis Bellot, Project Lead of ServiceStack - Part 1

    Interview With Demis Bellot, Project Lead of ServiceStack - Part 2 

    SignalR, Filters and ServiceStack

    翻译此页
     
    分类: WCFLinux/Mono

    目录

    背景volatile 的作用?何时使用 volatile?备注

    背景返回目录

    学了六年C#,一直没有使用过 volatile,对多线程编程也是偶尔才会使用,这次学习 Java 又遇到了 volatile,准备稍微深入的了解一下。

    volatile 的作用?返回目录

    几乎所有支持这个关键字的语言给出的解释都一样:阻止编译器对字段访问和赋值的优化,直接从字段所在的空间取值(可能是值,也可能是引用),而非引入寄存器等优化措施(跟编译器的实现有关)。

    使用 volatile 后对,字段的访问(this.field)和字段的赋值(this.filed = xxx)就是原子操作了,在多线程环境下,不需要使用 synchronized 进行访问,否则的话必须使用 synchronized 进行访问。

    何时使用 volatile?返回目录

    根据上文,我们很容易总结出一个规律:方法中只对字段就行了访问或赋值,volatile 和 synchronized可以结合使用,如下例:

    复制代码
     1 public class Program {
     2     static Object locked = new Object();
     3     static volatile int count;
     4 
     5     public static void main(String[] args) {
     6         // TODO Auto-generated method stub
     7         
     8          
     9     }
    10 
    11     static int getCount() {
    12         return count;
    13     }
    14 
    15     static void resetCount() {
    16         count = 1;
    17     }
    18 
    19     static void increaseCount() {
    20         synchronized (locked) {
    21             count++;
    22         }
    23     }
    24 }
    复制代码

    备注返回目录

    本文没有深入到编译后的字节码级别进行探讨(也有可能是影响JIT),所以不一定对,有深入了解的朋友,还请留言批评。

     
    分类: Java
  • 相关阅读:
    Java static 关键字 静态初始化块
    一致性哈希
    Java函数传递方式值传递
    Scala 小练习
    Scala 推荐递归编程
    白话 Scala 控制抽象
    函数柯里化(curry)
    Scala 闭包 closure
    Scala 参数(类型)推断
    xcode配置文件中,Architectures表示的意义
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3348719.html
Copyright © 2011-2022 走看看