• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
What is the ServiceStack?
 

What is the ServiceStack?

on

  • 2,282 views

What is it?

What is it?
Where did it come from?
What does it do?

Statistics

Views

Total Views
2,282
Views on SlideShare
1,019
Embed Views
1,263

Actions

Likes
0
Downloads
12
Comments
0

3 Embeds 1,263

http://www.servicestack.net 1118
http://servicestack.net 143
http://schemas.servicestack.net 2

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n

What is the ServiceStack? What is the ServiceStack? Presentation Transcript

  • What is the ServiceStack
  • What is the ServiceStackhttp://www.servicestack.net https://github.com/ServiceStack Demis Bellot @demisbellot https://github.com/mythz http://www.servicestack.net/mythz_blog/ Core Team Steffen Müller @arxisos http://careers.stackoverflow.com/mythz Sergey Bogdanov @desunit
  • What is the ServiceStack • What is it? • Where did it come from? • What does it do?
  • More than Services Simple - Fast - Lightweight - Testable - Clean ServiceStack.Text ServiceStack.Redis .NET’s fastest JSON, JSV, CSV Text Serializers .NET’s leading Redis Client ServiceStack.OrmLite ServiceStack.Caching Fast, typed, Code-First Micro ORM Clean Caching Provider InterfacesSQL Server, Sqlite, PostgreSQL, MySQL, Oracle, Firebird In-Memory, Redis, Memcached, Azure, Disk More: node.js-powered Bundler, Logging, Auto-Mappers, Service Clients, Markdown Razor, Configuration Providers, Enhanced Funq IOC
  • More than Services Simple - Fast - Lightweight - Testable - Clean ServiceStack.Text ServiceStack.Redis .NET’s fastest JSON, JSV, CSV Text Serilaizers .NET’s leading Redis Client Code-First POCOs ServiceStack.OrmLite ServiceStack.Caching Fast, typed, Code-First Micro ORM Clean Caching Provider InterfacesSQL Server, Sqlite, PostgreSQL, MySQL, Oracle, Firebird In-Memory, Redis, Memcached, Azure, Disk More: node.js-powered Bundler, Logging, Auto-Mappers, Service Clients, Markdown Razor, Configuration Providers, Enhanced Funq IOC
  • Simple Demo Poco Power
  • Implementation var appSettings = new AppSettings(); var config = appSettings.Get<Config>("my.config", new Config { GitHubName = "mythz", TwitterName = "ServiceStack" });Object graphs in Config deserialize into clean POCOs:<appSettings name=”my.config” value=”{GitHubName:mythz,TwitterName:ServiceStack}”/> var github = new GithubGateway(); var repos = github.GetAllUserAndOrgsReposFor(config.GitHubName);Avoid Web.Config completely with sensible default values var twitter = new TwitterGateway(); var tweets = twitter.GetTimeline(config.TwitterName); External providers to return clean POCOs "Loaded {0} repos and {1} tweets...".Print(repos.Count, tweets.Count); OrmLiteConfig.DialectProvider = SqliteDialect.Provider; //using (IDbConnection db = "~/db.sqlite".MapAbsolutePath().OpenDbConnection()) Use Extension methods to: using (IDbConnection db = ":memory:".OpenDbConnection()) { db.DropAndCreateTable<Tweet>(); • DRY logic db.DropAndCreateTable<GithubRepo>(); • Create readable code • Avoid abstractions / restrictions "nInserting {0} Tweets into Sqlite:".Print(tweets.Count); db.InsertAll(tweets); • Allow extensibility "nLatest {0} Tweets from Sqlite:".Print(Show); db.Select<Tweet>(q => q.OrderByDescending(x => x.Id).Limit(Show)).PrintDump(); "nInserting {0} Repos into Sqlite:".Print(repos.Count); Code-First POCOs db.InsertAll(repos); "nLatest {0} Repos from Sqlite:".Print(Show); • Master authority of your models db.Select<GithubRepo>(q => q.OrderByDescending(x => x.Id).Limit(Show)).PrintDump(); • Start from C# project out } • Schema’s inferred from POCO’s using (var redis = new RedisClient()) • Reduce industrial knowledge { • Use Conventions where possible "nInserting {0} Tweets into Redis:".Print(tweets.Count); redis.StoreAll(tweets); • Typed API "n{0} Tweets from Redis:".Print(Show); • Intelli-sense & productivity redis.GetAll<Tweet>().Take(Show).PrintDump(); • Refactoring "nInserting {0} Repos into Redis:".Print(repos.Count); • Correctness redis.StoreAll(repos); "n{0} Repos from Redis:".Print(Show); redis.GetAll<GithubRepo>().Take(Show).PrintDump(); }
  • Benchmarks https://github.com/mythz/ScalingDotNETBrad Abrams (Google employee, former Microsoft PM and co-author of .NET Framework Design Guidelines)
  • OrmLite Benchmarks
  • JSON Benchmarks
  • Redis vs RavenDB Benchmarks
  • @ServiceStack favorites: Popular 114 Contributors Since July 2011https://github.com/ServiceStack/ServiceStack/wiki/Contributors http://www.servicestack.net/100k-downloads/
  • Where it began?Enterprise .NET 2007
  • Where it began?Followed the .NET Enterprise Play Book• Leveraged external Enterprise consultants• Adopted Microsofts prescribed Enterprise SOA solution at the time: CSF, WCF and BizTalk• We had an Enterprise / Technical Architect round-table• Split Internal systems into different independent SOA services (we really wanted to do SOA :)• Enterprise architects defined web service contracts using UML and XSDs: • XSD Messages were implementation ignorant • Explicitly validated XSD conformance at runtime • Leveraged SOAP/XML/XSD: Headers, Inheritance, Namespaces • UML -> XSDs -> DTOs -> used in WCF Service Contracts -> WSDLs -> Service Reference Proxies• CSFs state-full session was used as a Bus orchestrating communication between services• Services were discoverable, participating in CSFs Session• Service endpoints were WCF Services, leveraged SOAP headers for extra WS-* compliance• Wrote code Designed perfectly normalized databases
  • What happened? Disaster Code-gen DTOs were:• Brittle: A simple namespace change would break existing messages• Infectious: Domain logic binded to code-gen DTOs and version changes led to multiple parallel implementations• Friction-encumbered: Services needed to be built/ deployed in lock-step with each other We pioneered:• Xml everywhere: We had XML config to manage our XML- configured services and resources• Week-long downtimes: between breaking major upgrades, required to flush old messages out of the system• Glacial Development: The turn-around time to get a field from UML/XSD/dll to C# was measured in days• Enterprise Hacks: Added "ViewBags" to most messages to allow us to stuff arbitrary data in existing messages without changing the schema
  • What happened?• SOAP • Frail, Slow, Poor programmatic fit, Only accessible to SOAP Clients, Incompatible impls• RPC method signatures • Brittle, promotes lots of chatty client-specific API, Typed-API mandates code-gen, blurred service layer• Code-Gen • Changes breaks code, inhibits DRY, forces abstraction, multiple versions results in parallel implementations• Bus / State-full Sessions • Less accessible, harder to debug and test, easier to fail
  • What we did right?• SOA Design: Coarse-grained, well-defined, self-describing, time-decoupled, re-usable messages• Pub/Sub: Promotes the most loosely coupled architecture i.e. Sender decoupled from Receiver• Message Queues: Replay-able async idempotent messages provide the most reliable and durable inter-service communications• Martin Fowler & Co knew what the best-practices for remote services were: • Remote Facade: Using message-based, coarse-grained/batch-full interfaces minimizing round-trips, promoting creation of fewer but tolerant and version-able service interfaces • DTOs: Avoid any effort expended dealing with wire-format in application code • Gateway: Removes comms logic in app code and provides a swappable comms layer with a good isolation and testing abstraction
  • What is a Service?
  • What is a Service?What it’s notIts NOT to force the use of a particular technology or platformIts NOT to conform to a pre-defined specification or constraintsIts NOT to use a pre-determined format or follow a pre-scribed architecture
  • What is a Service? Its to provide a service
  • What is a Service?Its to provide a serviceto encapsulate some re-usable capabilities and make them available remotely
  • What is a Service?Its to provide a serviceto encapsulate some re-usable capabilities and make them available remotely ★ To as many clients as possible ★ In the most accessible and interoperable way ★ With the least amount of effort ★ With maximum amount of re-useGood characteristics ★ Version-able, tolerant and resilient to changes ★ End-to-end productivity Legend: ★ Goals that ServiceStack is optimized for :)
  • mflowLess 1/2 development team Magnitude more resultsBest-Practices SOA PlatformFaster, more scalable services ServiceStack was born
  • Visualizing ServiceStackBuilt on raw ASP.NET IHttpHandler’s Stand-alone HttpListener, MQ, RCON hosts Runs Everywhere Clean Slate using Code-First POCO’s New Auth, Caching, Session Providers
  • Visualizing ServiceStack
  • Visualizing ServiceStack
  • Advantages of Message-based Services• Theyre easy to version and evolve as youre freely able to add/remove functionality without error• Theyre easy to route, chain, hijack and decorate through to different handlers and pipelines• Theyre easy to serialize and proxy through to remote services• Theyre easy to log, record, defer and replay• Theyre easy to map and translate to and from domain models• Ideal for concurrency as immutable messages are thread-safe and are easily multiplexed• Theyre easy to extend with generic solutions and re-usable functionality around https://github.com/ServiceStack/ServiceStack/wiki/Advantages-of-message-based-web-services
  • Message-based remote services are everywhereConcurrency in F# – Part III – Erlang Style Message Passing type Message = Word of string | Fetch of IChannel<Map<string,int>> | Stoptype WordCountingAgent() =    let counter = MailboxProcessor.Start(fun inbox ->             let rec loop(words : Map<string,int>) =                async { let! msg = inbox.Receive()                        match msg with                        | Word word ->                            if words.ContainsKey word then                                let count = words.[word]                                let words = words.Remove word                                return! loop(words.Add (word, (count + 1)) )                            else                                return! loop(words.Add (word, 1) )                        | Stop ->                            return ()                        | Fetch replyChannel ->                            do replyChannel.Post(words) //post to reply channel and continue                            return! loop(words) }              loop(Map.empty)) //The initial state     member a.AddWord(n) = counter.Post(Word(n))    member a.Stop() = counter.Post(Stop)    member a.Fetch() = counter.PostSync(fun replyChannel -> Fetch(replyChannel)) http://strangelights.com/blog/archive/2007/10/24/1601.aspx
  • Message-based remote services are everywhereGoogle Protocol Buffer Messages http://code.google.com/p/protobuf/message Person {  required int32 id = 1;  required string name = 2;  optional string email = 3;}Amazon C# SDK Petboard: An ASP.NET Sample Using Amazon S3 and Amazon SimpleDBSelectRequest selectRequest = new SelectRequest()    .WithSelectExpression("select * from `petboard-public`");SelectResponse selectResponse = _simpleDBClient.Select(selectRequest); http://aws.amazon.com/articles/3592
  • Message-based remote services are everywhere Scala Actors Actors in Go type ReadReq struct { import scala.actors.Actor._   key string import java.net.{InetAddress, UnknownHostException}   ack chan<- string } case class LookupIP(name: String, respondTo: Actor) type WriteReq struct { case class LookupResult(   key, val string   name: String, }   address: Option[InetAddress] ) c := make(chan interface{}) object NameResolver extends Actor { go func() {   def act() {   m := make(map[string]string)     loop {   for {       react {     switch r := (<-c).(type) {         case LookupIP(name, actor) =>     case ReadReq:           actor ! LookupResult(name, getIp(name))       r.ack <- m[r.key]       }     case WriteReq:     }       m[r.key] = r.val   }     } }   } }()http://www.cs.helsinki.fi/u/wikla/OTS/Sisalto/examples/html/ch30.html https://docs.google.com/present/view?id=df36r82q_5gdq5gzth
  • non-message-based service examples
  • non-message-based service examples namespace HelloWebAPI.Controllers Your First ASP.NET Web API (C#) Tutorial: {     public class ProductsController : ApiController     {         Product[] products = new Product[]         {             new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 },             new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M },             new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M }         };         public IEnumerable<Product> GetAllProducts()         {             return products;         }         public Product GetProductById(int id)         {             var product = products.FirstOrDefault((p) => p.Id == id);             if (product == null)             {                 throw new HttpResponseException(HttpStatusCode.NotFound);             }             return product;         }         public IEnumerable<Product> GetProductsByCategory(string category)         {             return products.Where(                 (p) => string.Equals(p.Category, category,                     StringComparison.OrdinalIgnoreCase));         }     } }http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api
  • Your First ASP.NET Web API (C#) Tutorial: The Same Services in ServiceStack: public class ProductsControllerV2 : ApiController public class FindProducts : IReturn<List<Product>>    {     {        public IEnumerable<Product> GetAllProducts()         public string Category { get; set; }        {         public decimal? PriceGreaterThan { get; set; }            return products;     }        }     public class GetProduct : IReturn<Product>        public Product GetProductById(int id)     {        {         public int? Id { get; set; }            var product = products.FirstOrDefault((p) => p.Id == id);         public string Name { get; set; }            if (product == null)     }            {                throw new HttpResponseException(HttpStatusCode.NotFound);     public class ProductsService : IService            }     {            return product;         public object Get(FindProducts request)        }         {             var ret = products.AsQueryable();        public Product GetProductByName(string categoryName)             if (request.Category != null)        {                 ret = ret.Where(x => x.Category == request.Category);            var product = products.FirstOrDefault((p) => p.Name == categoryName);             if (request.PriceGreaterThan.HasValue)            if (product == null)                 ret = ret.Where(x => x.Price > request.PriceGreaterThan.Value);            {             return ret;                throw new HttpResponseException(HttpStatusCode.NotFound);         }            }            return product;         public object Get(GetProduct request)        }         {             var product = request.Id.HasValue        //Extending existing services by adding more RPC method calls                 ? products.FirstOrDefault(x => x.Id == request.Id.Value)        public IEnumerable<Product> GetProductsByCategory(string category)                 : products.FirstOrDefault(x => x.Name == request.Name);        {            return products.Where(             if (product == null)                (p) => string.Equals(p.Category, category,                 throw new HttpError(HttpStatusCode.NotFound, "Product does not exist");                    StringComparison.OrdinalIgnoreCase));        }             return product;         }        public IEnumerable<Product> GetProductsByPriceGreaterThan(decimal price)     }        {            return products.Where((p) => p.Price > price);        } //Design of new services based on calling semantics and Return type,    } //e.g. Find* filters results, whilst Get* fetches unique records:
  • Familiar?WCF-Style Services vs ServiceStack Web Services public class Customers {public interface IService int[] Ids;{ string[] UserNames; Customer GetCustomerById(int id); string[] Emails; Customer[] GetCustomerByIds(int[] id); } Customer GetCustomerByUserName(string userName); Customer[] GetCustomerByUserNames(string[] userNames); public class CustomersResponse { Customer GetCustomerByEmail(string email); Customer[] Results; Customer[] GetCustomerByEmails(string[] emails); }}Any combination of the above can be fulfilled by 1 remote call, by the same single web service - i.e what ServiceStack encouragesFewer and more batch-full services require less maintenance and promote the development of more re-usable and efficient services. In addition, message APIs are much moreresilient to changes as youre able to safely add more functionality or return more data without breaking or needing to re-gen existing clients. Message-based APIs also lend thembetter for cached, asynchronous, deferred, proxied and reliable execution with the use of brokers and proxies.
  • Calling the Product Services in ServiceStack     private const string BaseUri = "http://localhost:1337";   /* All Products:     IRestClient client = new JsonServiceClient(BaseUri); [ {     "nAll Products:".Print(); Id: 1,     client.Get(new FindProducts()).PrintDump(); Name: Tomato Soup, Category: Groceries, Price: 1 }, { Id: 2, Name: Yo-yo, Category: Toys, // Notes: Price: 3.75 // - No Code-Gen: Same generic service client used for all operations }, // - When Custom Routes are specified it uses those, otherwise falls back to pre-defined routes { // - IRestClient interface implemented by JSON, JSV, Xml, MessagePack, ProtoBuf Service Clients Id: 3, // - Service returns IEnumerable[Product] but JSON, JSV serializers happily handles List[Product] fine Name: Hammer, Category: Hardware, Price: 16.99 } ] */     /* Toy Products:     List<Product> toyProducts = client.Get(new FindProducts { Category = "Toys" }); [     "nToy Products:".Print(); {     toyProducts.PrintDump(); Id: 2, Name: Yo-yo, Category: Toys, Price: 3.75 } ] */
  • Calling the Product Services in ServiceStack    List<Product> productsOver2Bucks = client.Get(new FindProducts { PriceGreaterThan = 2 });     /* Products over $2:    "nProducts over $2:".Print(); [    productsOver2Bucks.PrintDump(); { Id: 2, Name: Yo-yo, Category: Toys, Price: 3.75 }, { Id: 3, Name: Hammer, Category: Hardware, Price: 16.99 } ] */    var hardwareOver2Bucks = client.Get(new FindProducts {PriceGreaterThan=2, Category="Hardware"});     /* Hardware over $2:    "nHardware over $2:".Print(); [    hardwareOver2Bucks.PrintDump(); { Id: 3, Name: Hammer, Category: Hardware, Price: 16.99 } ] */    Product product1 = client.Get(new GetProduct { Id = 1 });    /* Product with Id = 1:    "nProduct with Id = 1:".Print(); {    product1.PrintDump(); Id: 1, Name: Tomato Soup, Category: Groceries, Price: 1 } */
  • Testable New API Tests protected static IRestClient[] RestClients = [Test, TestCaseSource("RestClients")] { public void Can_GET_AllReqstars(IRestClient client) new JsonServiceClient(BaseUri), { new XmlServiceClient(BaseUri), var allReqstars = client.Get<List<Reqstar>>("/reqstars"); new JsvServiceClient(BaseUri), Assert.That(allReqstars.Count, Is.EqualTo(ReqstarsService.SeedData.Length)); new MsgPackServiceClient(BaseUri), } } ; [Test, TestCaseSource("ServiceClients")] protected static IServiceClient[] ServiceClients = public void Can_SEND_AllReqstars_PrettyTypedApi(IServiceClient client) RestClients.OfType<IServiceClient>().ToArray(); { var allReqstars = client.Send(new AllReqstars()); Assert.That(allReqstars.Count, Is.EqualTo(ReqstarsService.SeedData.Length)); } https://github.com/ServiceStack/ServiceStack/blob/master/tests/RazorRockstars.Console.Files/ReqStarsService.cs Same Unit Test can be re-used in JSON, XML, JSV, SOAP 1.1/1.2 Integration Tests https://github.com/ServiceStack/ServiceStack/blob/master/tests/ServiceStack.WebHost.IntegrationTests/Tests/WebServicesTests.cs
  • Frictionless Productive end-to-end typed pipeline
  • ServiceStack Demo Hello, World! http://tinyurl.com/hellomonkeyspace
  • Hello World Implementation[Route("/hellohtml/{Name}")] public class HelloService : Service {public class HelloHtml public object Get(HelloHtml request) {{ return "<h1>Hello, {0}!</h1>".Fmt(request.Name); public string Name { get; set; } }} [AddHeader(ContentType = "text/plain")] public object Get(HelloText request) {[Route("/hellotext/{Name}")] return "<h1>Hello, {0}!</h1>".Fmt(request.Name);public class HelloText }{ [AddHeader(ContentType = "image/png")] public string Name { get; set; } public object Get(HelloImage request) {} var width = request.Width.GetValueOrDefault(640); var height = request.Height.GetValueOrDefault(360);[Route("/helloimage/{Name}")] var bgColor = request.Background != null ? Color.FromName(request.Background) : Color.ForestGreen;public class HelloImage var fgColor = request.Foreground != null ? Color.FromName(request.Foreground) : Color.White;{ var image = new Bitmap(width, height); public string Name { get; set; } using (var g = Graphics.FromImage(image)) { g.Clear(bgColor); public int? Width { get; set; } var drawString = "Hello, {0}!".Fmt(request.Name); public int? Height { get; set; } var drawFont = new Font("Times", request.FontSize.GetValueOrDefault(40)); public int? FontSize { get; set; } var drawBrush = new SolidBrush(fgColor); public string Foreground { get; set; } var drawRect = new RectangleF(0, 0, width, height); public string Background { get; set; } var drawFormat = new StringFormat {} LineAlignment = StringAlignment.Center, Alignment = StringAlignment.Center }; [Route("/hello/{Name}")] g.DrawString(drawString, drawFont, drawBrush, drawRect, drawFormat);public class Hello : IReturn<HelloResponse> var ms = new MemoryStream();{ image.Save(ms, ImageFormat.Png); public string Name { get; set; } return ms;} } }public class HelloResponse public object Get(Hello request) {{ return new HelloResponse { Result = "Hello, {0}!".Fmt(request.Name) }; public string Result { get; set; } }} } C# Client calls with: //var response = client.Get(new Hello { Name = "ServiceStack" });
  • ServiceStack Demo SMessage
  • SMessage Implementation public partial class SMessageService : Service public partial class SMessageService : Service { { public EmailProvider Email { get; set; } public object Any(EmailMessage request) public FacebookGateway Facebook { get; set; } { public TwitterGateway Twitter { get; set; } var sw = Stopwatch.StartNew(); public IMessageFactory MsgFactory { get; set; } Db.InsertAll(Email.Process(request)); return new SMessageResponse { TimeTakenMs = sw.ElapsedMilliseconds }; public object Any(SMessage request) } { var sw = Stopwatch.StartNew(); public object Any(CallFacebook request) { if (!request.Defer) var sw = Stopwatch.StartNew(); { Db.InsertAll(Facebook.Process(request)); var results = new List<SMessageReceipt>(); return new SMessageResponse { TimeTakenMs = sw.ElapsedMilliseconds }; results.AddRange(Email.Send(request)); } results.AddRange(Facebook.Send(request)); results.AddRange(Twitter.Send(request)); public object Any(PostStatusTwitter request) Db.InsertAll(results); { } var sw = Stopwatch.StartNew(); else Db.InsertAll(Twitter.Process(request)); { return new SMessageResponse { TimeTakenMs = sw.ElapsedMilliseconds }; using (var producer = MsgFactory.CreateMessageProducer()) } { Email.CreateMessages(request).ForEach(producer.Publish); public object Any(FindReceipts request) Facebook.CreateMessages(request).ForEach(producer.Publish); { Twitter.CreateMessages(request).ForEach(producer.Publish); var skip = request.Skip.GetValueOrDefault(0); } var take = request.Take.GetValueOrDefault(20); } return Db.Select<SMessageReceipt>(q => q.Limit(skip, take)); } return new SMessageResponse { } TimeTakenMs = sw.ElapsedMilliseconds, }; } }
  • Why Mono?
  • Why Mono? Scale at $0 licensing cost Bring .NET to exciting Platforms
  • Why Mono? Scale at $0 licensing cost • Redis • PostgreSQL, MySQL, SQLite, Firebird Lets build the next Instagram!
  • Why Mono? Scale at $0 licensing cost Where to host servicestack.net?
  • Why Mono? Scale at $0 licensing cost 2.67 GHz 1.67 GHz 2GB RAM Where to host 1.75GB RAM servicestack.net? 80GB HDD 100GB HDD 4TB traffic 2TB traffic
  • Why Mono? Scale at $0 licensing cost 2.67 GHz 1.67 GHz 2GB RAM Where to host 1.75GB RAM servicestack.net? 80GB HDD 100GB HDD 4TB traffic 2TB traffic €19.90 mo > 11x Cheaper! €219.50 mo €238.8 year €2,634 year
  • Why Mono? Bring .NET to exciting Platforms
  • Features:
  • Sergey Bogdanov @desunitFeatures: Swagger Integration
  • Sergey Bogdanov @desunitFeatures: Swagger Integration
  • https://github.com/ServiceStack/ServiceStack/wiki/Authentication-and-authorizationFeatures: Authentication Providers var appSettings = new AppSettings(); Plugins.Add(new AuthFeature( () => new CustomUserSession(), //Use your own typed Custom UserSession type new IAuthProvider[] {                     new CredentialsAuthProvider(), //HTML Form post of UserName/Password credentials                     new TwitterAuthProvider(appSettings), //Sign-in with Twitter                     new FacebookAuthProvider(appSettings), //Sign-in with Facebook                     new DigestAuthProvider(appSettings), //Sign-in with Digest Auth                     new BasicAuthProvider(), //Sign-in with Basic Auth                     new GoogleOpenIdOAuthProvider(appSettings), //Sign-in with Google OpenId                     new YahooOpenIdOAuthProvider(appSettings), //Sign-in with Yahoo OpenId                     new OpenIdOAuthProvider(appSettings), //Sign-in with Custom OpenId                 })); https://github.com/ServiceStack/SocialBootstrapApi/
  • https://github.com/ServiceStack/ServiceStack/wiki/ValidationFeatures: Validation End-to-end typed API for exceptions try { var client = new JsonServiceClient(BaseUri); var response = client.Send<UserResponse>(new User()); } catch (WebServiceException webEx) { /* webEx.StatusCode = 400 webEx.ErrorCode = ArgumentNullException webEx.Message = Value cannot be null. Parameter name: Name webEx.StackTrace = (your Server Exception StackTrace - if DebugMode is enabled) webEx.ResponseDto = (your populated Response DTO) webEx.ResponseStatus = (your populated Response Status DTO) webEx.GetFieldErrors() = (individual errors for each field if any) */ } https://github.com/ServiceStack/ServiceStack/wiki/Validation
  • https://github.com/ServiceStack/ServiceStack/wiki/CachingFeatures: Caching Providers container.Register<ICacheClient>(new MemoryCacheClient()); public class OrdersService : Service { public object Get(CachedOrders request) { var cacheKey = "unique_key_for_this_request"; return base.RequestContext.ToOptimizedResultUsingCache(base.Cache, cacheKey, () => { //Delegate is executed if item doesnt exist in cache //Any response DTO returned here will be cached automatically } ); } } Redis, Memcached, Disk and Azure Caching Providers also available Sessions works with any Cache Provider http://www.servicestack.net/ServiceStack.Northwind/
  • https://github.com/ServiceStack/ServiceStack/wiki/Request-loggerFeatures: Request Logger Query String Filters
  • https://github.com/ServiceStack/ServiceStack/wiki/Built-in-profilingFeatures: Mini Profiler Built-in protected void Application_BeginRequest(object src, EventArgs e) { if (Request.IsLocal) Profiler.Start(); } protected void Application_EndRequest(object src, EventArgs e) { Profiler.Stop(); }
  • http://careers.stackoverflow.com/mythz@ServiceStack Thank Youhttp://www.servicestack.net https://github.com/ServiceStack @demisbellot Questions? Core Team Steffen Müller @arxisos Sergey Bogdanov @desunit