Permalink
Browse files

Moved Contrib's ServiceStack.ServiceInterfaces.proj back into the Ser…

…viceStack repo so it builds better in Mono/MonoDevelop.
  • Loading branch information...
1 parent b3a724e commit 57af1ce217686d63355dd73ea0235106b709a6b5 @mythz mythz committed Jun 10, 2011
Showing with 2,006 additions and 34 deletions.
  1. BIN NuGet/ServiceStack/lib/ServiceStack.Common.dll
  2. BIN NuGet/ServiceStack/lib/ServiceStack.Interfaces.dll
  3. BIN NuGet/ServiceStack/lib/ServiceStack.dll
  4. BIN lib/ServiceStack.ServiceInterface.dll
  5. +60 −0 src/ServiceStack.ServiceInterface/AsyncServiceBase.cs
  6. +11 −0 src/ServiceStack.ServiceInterface/Config.cs
  7. +37 −0 src/ServiceStack.ServiceInterface/Properties/AssemblyInfo.cs
  8. +21 −0 src/ServiceStack.ServiceInterface/README.md
  9. +90 −0 src/ServiceStack.ServiceInterface/RestServiceBase.cs
  10. +283 −0 src/ServiceStack.ServiceInterface/ServiceBase.cs
  11. +120 −0 src/ServiceStack.ServiceInterface/ServiceModel/ResponseStatusTranslator.cs
  12. +47 −0 src/ServiceStack.ServiceInterface/ServiceResponseException.cs
  13. +162 −0 src/ServiceStack.ServiceInterface/ServiceStack.ServiceInterface.csproj
  14. +157 −0 src/ServiceStack.ServiceInterface/Session/CachedUserSessionManager.cs
  15. +80 −0 src/ServiceStack.ServiceInterface/Session/IUserSessionManager.cs
  16. +30 −0 src/ServiceStack.ServiceInterface/Session/PublicAndPrivateClientSessions.cs
  17. +86 −0 src/ServiceStack.ServiceInterface/Session/UserClientSession.cs
  18. +174 −0 src/ServiceStack.ServiceInterface/Session/UserSession.cs
  19. +39 −0 src/ServiceStack.ServiceInterface/Testing/BasicAppHost.cs
  20. +98 −0 src/ServiceStack.ServiceInterface/Testing/MockHttpRequest.cs
  21. +54 −0 src/ServiceStack.ServiceInterface/Testing/TestAppHost.cs
  22. +394 −0 src/ServiceStack.ServiceInterface/Testing/TestBase.cs
  23. +33 −0 src/ServiceStack.sln
  24. +4 −4 tests/MasterHost/MasterHost.csproj
  25. +0 −3 tests/ServiceStack.Common.Tests/ServiceStack.Common.Tests.csproj
  26. +4 −3 tests/ServiceStack.Messaging.Tests/ServiceStack.Messaging.Tests.csproj
  27. +9 −9 tests/ServiceStack.Messaging.Tests/Services/MessagingServiceBase.cs
  28. +4 −3 tests/ServiceStack.ServiceHost.Tests/ServiceStack.ServiceHost.Tests.csproj
  29. +0 −4 tests/ServiceStack.ServiceModel.Tests/ServiceStack.ServiceModel.Tests.csproj
  30. +5 −5 tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStack.WebHost.Endpoints.Tests.csproj
  31. +4 −3 tests/ServiceStack.WebHost.IntegrationTests/ServiceStack.WebHost.IntegrationTests.csproj
View
BIN NuGet/ServiceStack/lib/ServiceStack.Common.dll
Binary file not shown.
View
BIN NuGet/ServiceStack/lib/ServiceStack.Interfaces.dll
Binary file not shown.
View
BIN NuGet/ServiceStack/lib/ServiceStack.dll
Binary file not shown.
View
BIN lib/ServiceStack.ServiceInterface.dll
Binary file not shown.
View
60 src/ServiceStack.ServiceInterface/AsyncServiceBase.cs
@@ -0,0 +1,60 @@
+using System;
+using ServiceStack.Messaging;
+using ServiceStack.ServiceHost;
+
+namespace ServiceStack.ServiceInterface
+{
+ /// <summary>
+ /// Useful base functionality for IAsyncServices by serializing the request
+ /// into the message queue configured by the AppHost if one is configured.
+ ///
+ /// This allows the request to persist for longer than the request duration
+ /// and can defer the execution of the async request under optimal execution.
+ ///
+ /// If one is not configured it will Execute the request immediately as per normal.
+ /// </summary>
+ /// <typeparam name="TRequest"></typeparam>
+ public abstract class AsyncServiceBase<TRequest>
+ : ServiceBase<TRequest>, IAsyncService<TRequest>
+ {
+ /// <summary>
+ /// Injected by the ServiceStack IOC with the registered dependency in the Funq IOC container.
+ /// </summary>
+ public IMessageFactory MessageFactory { get; set; }
+
+ /// <summary>
+ /// Persists the request into the registered message queue if configured,
+ /// otherwise calls Execute() to handle the request immediately.
+ /// </summary>
+ /// <param name="request"></param>
+ public virtual object ExecuteAsync(TRequest request)
+ {
+ if (MessageFactory == null)
+ {
+ return Execute(request);
+ }
+
+ //Capture and persist this async request on this Services 'In Queue'
+ //for execution after this request has been completed
+ using (var producer = MessageFactory.CreateMessageProducer())
+ {
+ producer.Publish(request);
+ }
+
+ return CreateResponseDto(request);
+ }
+
+ /// <summary>
+ /// The Deferred execution of ExecuteAsync(request)'s.
+ /// This request is typically invoked from a messaging queue service host.
+ /// </summary>
+ /// <param name="request"></param>
+ public virtual object ExecuteAsync(IMessage<TRequest> request)
+ {
+ return Run(request.Body);
+ }
+
+ }
+
+
+}
View
11 src/ServiceStack.ServiceInterface/Config.cs
@@ -0,0 +1,11 @@
+namespace ServiceStack.ServiceInterface
+{
+ public class Config
+ {
+ /// <summary>
+ /// Would've preferred to use [assembly: ContractNamespace] attribute but it is not supported in Mono
+ /// </summary>
+ //public const string DefaultNamespace = "http://schemas.sericestack.net/examples/types";
+ public const string DefaultNamespace = "http://schemas.servicestack.net/types";
+ }
+}
View
37 src/ServiceStack.ServiceInterface/Properties/AssemblyInfo.cs
@@ -0,0 +1,37 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ServiceStack.OperationContext")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ServiceStack.OperationContext")]
+[assembly: AssemblyCopyright("Copyright © 2010")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("b1eeca45-c9f8-457d-a6ee-98ac3b071639")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.*")]
+//[assembly: AssemblyFileVersion("1.0.0.0")]
+
+//Default DataContract namespace instead of tempuri.org
View
21 src/ServiceStack.ServiceInterface/README.md
@@ -0,0 +1,21 @@
+# Useful high-level App and use-case specific features and utils
+
+The ServiceBase and RestServiceBase classes provide use-ful base classes for your web services to inherit from.
+
+### ServiceBase - base class for RPC services
+
+ * Handles C# exceptions and serializes them into your Response DTO's so your clients can programatically access them
+ * If you have a IRedisClient installed, rolling error logs will be maintained so you can easily see the latest errors
+ * **base.ResolveService()** - let's you access a pre-configured instance of another web service so you can delegate required functionality
+ * **base.AppHost** - Accesses the underlying AppHost letting you inspect its configuration, etc
+
+### RestServiceBase - base class for REST Services (extends ServiceBase)
+
+ * Reduces the boiler-plate by already implementing all REST operations so you don't have to e.g. IRestGetService<TRequest>
+
+
+### ServiceModel
+Generic DTO types useful for all web services. e.g. **ResponseStatus** is where C# exceptions get injected into
+
+### Session
+Existing classes
View
90 src/ServiceStack.ServiceInterface/RestServiceBase.cs
@@ -0,0 +1,90 @@
+using System;
+using ServiceStack.ServiceHost;
+
+namespace ServiceStack.ServiceInterface
+{
+ public abstract class RestServiceBase<TRequest>
+ : ServiceBase<TRequest>,
+ IRestGetService<TRequest>,
+ IRestPutService<TRequest>,
+ IRestPostService<TRequest>,
+ IRestDeleteService<TRequest>
+ {
+ protected override object Run(TRequest request)
+ {
+ throw new NotImplementedException("This base method should be overridden but not called");
+ }
+
+ public virtual object OnGet(TRequest request)
+ {
+ throw new NotImplementedException("This base method should be overridden but not called");
+ }
+
+ public object Get(TRequest request)
+ {
+ try
+ {
+ OnBeforeExecute(request);
+ return OnGet(request);
+ }
+ catch (Exception ex)
+ {
+ return HandleException(request, ex);
+ }
+ }
+
+ public virtual object OnPut(TRequest request)
+ {
+ throw new NotImplementedException("This base method should be overridden but not called");
+ }
+
+ public object Put(TRequest request)
+ {
+ try
+ {
+ OnBeforeExecute(request);
+ return OnPut(request);
+ }
+ catch (Exception ex)
+ {
+ return HandleException(request, ex);
+ }
+ }
+
+ public virtual object OnPost(TRequest request)
+ {
+ throw new NotImplementedException("This base method should be overridden but not called");
+ }
+
+ public object Post(TRequest request)
+ {
+ try
+ {
+ OnBeforeExecute(request);
+ return OnPost(request);
+ }
+ catch (Exception ex)
+ {
+ return HandleException(request, ex);
+ }
+ }
+
+ public virtual object OnDelete(TRequest request)
+ {
+ throw new NotImplementedException("This base method should be overridden but not called");
+ }
+
+ public object Delete(TRequest request)
+ {
+ try
+ {
+ OnBeforeExecute(request);
+ return OnDelete(request);
+ }
+ catch (Exception ex)
+ {
+ return HandleException(request, ex);
+ }
+ }
+ }
+}
View
283 src/ServiceStack.ServiceInterface/ServiceBase.cs
@@ -0,0 +1,283 @@
+using System;
+using System.Net;
+using ServiceStack.Common;
+using ServiceStack.Common.Utils;
+using ServiceStack.Common.Web;
+using ServiceStack.Logging;
+using ServiceStack.Redis;
+using ServiceStack.ServiceHost;
+using ServiceStack.ServiceInterface.ServiceModel;
+using ServiceStack.Text;
+using ServiceStack.WebHost.Endpoints;
+
+namespace ServiceStack.ServiceInterface
+{
+
+ /// <summary>
+ /// A Useful ServiceBase for all services with support for automatically serializing
+ /// Exceptions into a common ResponseError DTO so errors can be handled generically by clients.
+ ///
+ /// If an 'IRedisClientsManager' is configured in your AppHost, service errors will
+ /// also be maintained into a service specific and combined rolling error log.
+ /// </summary>
+ /// <typeparam name="TRequest"></typeparam>
+ public abstract class ServiceBase<TRequest>
+ : IService<TRequest>, IRequiresRequestContext
+ {
+ private static readonly ILog Log = LogManager.GetLogger(typeof(ServiceBase<>));
+
+ /// <summary>
+ /// Naming convention for the request's Response DTO
+ /// </summary>
+ public const string ResponseDtoSuffix = "Response";
+
+ /// <summary>
+ /// Naming convention for the ResponseStatus property name on the response DTO
+ /// </summary>
+ public const string ResponseStatusPropertyName = "ResponseStatus";
+
+ /// <summary>
+ /// Service error logs are kept in 'urn:ServiceErrors:{ServiceName}'
+ /// </summary>
+ public const string UrnServiceErrorType = "ServiceErrors";
+
+ /// <summary>
+ /// Combined service error logs are maintained in 'urn:ServiceErrors:All'
+ /// </summary>
+ public const string CombinedServiceLogId = "All";
+
+
+ /// <summary>
+ /// Can be overriden to supply Custom 'ServiceName' error logs
+ /// </summary>
+ public virtual string ServiceName
+ {
+ get { return typeof(TRequest).Name; }
+ }
+
+ /// <summary>
+ /// Access to the Applications ServiceStack AppHost Instance
+ /// </summary>
+ private IAppHost appHost;
+ public virtual IAppHost AppHost
+ {
+ get
+ {
+ return appHost ?? EndpointHost.AppHost;
+ }
+ set
+ {
+ this.appHost = value;
+ }
+ }
+
+ public IRequestContext RequestContext { get; set; }
+
+ /// <summary>
+ /// Resolve an alternate Web Service from ServiceStack's IOC container.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <returns></returns>
+ public T ResolveService<T>()
+ {
+ var service = this.AppHost.TryResolve<T>();
+ var requiresContext = service as IRequiresRequestContext;
+ if (requiresContext != null)
+ {
+ requiresContext.RequestContext = this.RequestContext;
+ }
+ return service;
+ }
+
+ /// <summary>
+ /// Maintains the current request DTO in this property
+ /// </summary>
+ protected TRequest CurrentRequestDto;
+
+ /// <summary>
+ /// Override to provide additional/less context about the Service Exception.
+ /// By default the request is serialized and appended to the ResponseStatus StackTrace.
+ /// </summary>
+ public virtual string GetRequestErrorBody()
+ {
+ var requestString = "";
+ try
+ {
+ requestString = TypeSerializer.SerializeToString(CurrentRequestDto);
+ }
+ catch /*(Exception ignoreSerializationException)*/
+ {
+ //Serializing request successfully is not critical and only provides added error info
+ }
+
+ return string.Format("[{0}: {1}]:\n[REQUEST: {2}]", GetType().Name, DateTime.UtcNow, requestString);
+ }
+
+ protected T TryResolve<T>()
+ {
+ return this.AppHost == null
+ ? default(T)
+ : this.AppHost.TryResolve<T>();
+ }
+
+ /// <summary>
+ /// Single method sub classes should implement to execute the request
+ /// </summary>
+ /// <param name="request"></param>
+ /// <returns></returns>
+ protected abstract object Run(TRequest request);
+
+ /// <summary>
+ /// Called before the request is Executed. Override to enforce generic validation logic.
+ /// </summary>
+ /// <param name="request"></param>
+ protected virtual void OnBeforeExecute(TRequest request) { }
+
+ /// <summary>
+ /// Execute the request with the protected abstract Run() method in a managed scope by
+ /// provide default handling of Service Exceptions by serializing exceptions in the response
+ /// DTO and maintaining all service errors in a managed service-specific and combined rolling error logs
+ /// </summary>
+ /// <param name="request"></param>
+ /// <returns></returns>
+ public object Execute(TRequest request)
+ {
+ try
+ {
+ OnBeforeExecute(request);
+ return Run(request);
+ }
+ catch (Exception ex)
+ {
+ return HandleException(request, ex);
+ }
+ }
+
+ protected virtual object HandleException(TRequest request, Exception ex)
+ {
+ var responseStatus = ResponseStatusTranslator.Instance.Parse(ex);
+
+ if (EndpointHost.UserConfig.DebugMode)
+ {
+ // View stack trace in tests and on the client
+ responseStatus.StackTrace = GetRequestErrorBody() + ex;
+ }
+
+ Log.Error("ServiceBase<TRequest>::Service Exception", ex);
+
+ //If Redis is configured, maintain rolling service error logs in Redis (an in-memory datastore)
+ var redisManager = TryResolve<IRedisClientsManager>();
+ if (redisManager != null)
+ {
+ try
+ {
+ //Get a thread-safe redis client from the client manager pool
+ using (var client = redisManager.GetClient())
+ {
+ //Get a client with a native interface for storing 'ResponseStatus' objects
+ var redis = client.GetTypedClient<ResponseStatus>();
+
+ //Store the errors in predictable Redis-named lists i.e.
+ //'urn:ServiceErrors:{ServiceName}' and 'urn:ServiceErrors:All'
+ var redisSeriviceErrorList = redis.Lists[UrnId.Create(UrnServiceErrorType, ServiceName)];
+ var redisCombinedErrorList = redis.Lists[UrnId.Create(UrnServiceErrorType, CombinedServiceLogId)];
+
+ //Append the error at the start of the service-specific and combined error logs.
+ redisSeriviceErrorList.Prepend(responseStatus);
+ redisCombinedErrorList.Prepend(responseStatus);
+
+ //Clip old error logs from the managed logs
+ const int rollingErrorCount = 1000;
+ redisSeriviceErrorList.Trim(0, rollingErrorCount);
+ redisCombinedErrorList.Trim(0, rollingErrorCount);
+ }
+ }
+ catch (Exception suppressRedisException)
+ {
+ Log.Error("Could not append exception to redis service error logs", suppressRedisException);
+ }
+ }
+
+ var responseDto = CreateResponseDto(request, responseStatus);
+
+ if (responseDto == null)
+ {
+ throw ex;
+ }
+
+ var httpError = ex as IHttpError;
+ if (httpError != null)
+ {
+ httpError.Response = responseDto;
+ return httpError;
+ }
+
+ return new HttpResult(responseDto, null, HttpStatusCode.InternalServerError);
+ }
+
+ /// <summary>
+ /// Create an instance of the service response dto type and inject it with the supplied responseStatus
+ /// </summary>
+ /// <param name="request"></param>
+ /// <param name="responseStatus"></param>
+ /// <returns></returns>
+ protected static object CreateResponseDto(TRequest request, ResponseStatus responseStatus)
+ {
+ // Predict the Response message type name
+ // Get the type
+ var responseDtoType = AssemblyUtils.FindType(GetResponseDtoName(request));
+ var responseDto = CreateResponseDto(request);
+
+ if (responseDto == null)
+ return null;
+
+ // For faster serialization of exceptions, services should implement IHasResponseStatus
+ var hasResponseStatus = responseDto as IHasResponseStatus;
+ if (hasResponseStatus != null)
+ {
+ hasResponseStatus.ResponseStatus = responseStatus;
+ }
+ else
+ {
+ // Get the ResponseStatus property
+ var responseStatusProperty = responseDtoType.GetProperty(ResponseStatusPropertyName);
+
+ if (responseStatusProperty != null)
+ {
+ // Set the ResponseStatus
+ ReflectionUtils.SetProperty(responseDto, responseStatusProperty, responseStatus);
+ }
+ }
+
+ // Return an Error DTO with the exception populated
+ return responseDto;
+ }
+
+ /// <summary>
+ /// Create an instance of the response dto based on the requestDto type and default naming convention
+ /// </summary>
+ /// <param name="request"></param>
+ /// <returns></returns>
+ protected static object CreateResponseDto(TRequest request)
+ {
+ // Get the type
+ var responseDtoType = AssemblyUtils.FindType(GetResponseDtoName(request));
+
+ if (responseDtoType == null)
+ {
+ // We don't support creation of response messages without a predictable type name
+ return null;
+ }
+
+ // Create an instance of the response message for this request
+ var responseDto = ReflectionUtils.CreateInstance(responseDtoType);
+ return responseDto;
+ }
+
+ protected static string GetResponseDtoName(TRequest request)
+ {
+ return typeof(TRequest).FullName + ResponseDtoSuffix;
+ }
+ }
+
+}
View
120 src/ServiceStack.ServiceInterface/ServiceModel/ResponseStatusTranslator.cs
@@ -0,0 +1,120 @@
+/*
+// $Id: ResponseStatusTranslator.cs 12245 2010-02-23 14:55:31Z Demis Bellot $
+//
+// Revision : $Revision: 12245 $
+// Modified Date : $LastChangedDate: 2010-02-23 14:55:31 +0000 (Tue, 23 Feb 2010) $
+// Modified By : $LastChangedBy: Demis Bellot $
+//
+// (c) Copyright 2010 Liquidbit Ltd
+*/
+
+using System;
+using System.Collections.Generic;
+using ServiceStack.Common.Extensions;
+using ServiceStack.DesignPatterns.Translator;
+using ServiceStack.ServiceHost;
+using ServiceStack.Validation;
+
+namespace ServiceStack.ServiceInterface.ServiceModel
+{
+ /// <summary>
+ /// Translates a ValidationResult into a ResponseStatus DTO fragment.
+ /// </summary>
+ public class ResponseStatusTranslator
+ : ITranslator<ResponseStatus, ValidationResult>
+ {
+ public static readonly ResponseStatusTranslator Instance
+ = new ResponseStatusTranslator();
+
+ public ResponseStatus Parse(Exception exception)
+ {
+ var validationException = exception as ValidationException;
+ if (validationException != null)
+ {
+ return this.Parse(validationException);
+ }
+
+ var httpError = exception as IHttpError;
+ return httpError != null
+ ? CreateErrorResponse(httpError.ErrorCode, httpError.Message)
+ : CreateErrorResponse(exception.GetType().Name, exception.Message);
+ }
+
+ public ResponseStatus Parse(ValidationException validationException)
+ {
+ return CreateErrorResponse(validationException.ErrorCode, validationException.Message, validationException.Violations);
+ }
+
+ public ResponseStatus Parse(ValidationResult validationResult)
+ {
+ return validationResult.IsValid
+ ? CreateSuccessResponse(validationResult.SuccessMessage)
+ : CreateErrorResponse(validationResult.ErrorCode, validationResult.ErrorMessage, validationResult.Errors);
+ }
+
+ public static ResponseStatus CreateSuccessResponse(string message)
+ {
+ return new ResponseStatus { Message = message };
+ }
+
+ public static ResponseStatus CreateErrorResponse(string errorCode)
+ {
+ var errorMessage = errorCode.SplitCamelCase();
+ return CreateErrorResponse(errorCode, errorMessage, null);
+ }
+
+ public static ResponseStatus CreateErrorResponse(string errorCode, string errorMessage)
+ {
+ return CreateErrorResponse(errorCode, errorMessage, null);
+ }
+
+ /// <summary>
+ /// Creates the error response from the values provided.
+ ///
+ /// If the errorCode is empty it will use the first validation error code,
+ /// if there is none it will throw an error.
+ /// </summary>
+ /// <param name="errorCode">The error code.</param>
+ /// <param name="errorMessage">The error message.</param>
+ /// <param name="validationErrors">The validation errors.</param>
+ /// <returns></returns>
+ public static ResponseStatus CreateErrorResponse(string errorCode, string errorMessage, IEnumerable<ValidationError> validationErrors)
+ {
+ var to = new ResponseStatus
+ {
+ ErrorCode = errorCode,
+ Message = errorMessage,
+ };
+ if (validationErrors != null)
+ {
+ foreach (var validationError in validationErrors)
+ {
+ var error = new ResponseError
+ {
+ ErrorCode = validationError.ErrorCode,
+ FieldName = validationError.FieldName,
+ Message = validationError.ErrorMessage,
+ };
+ to.Errors.Add(error);
+
+ if (string.IsNullOrEmpty(to.ErrorCode))
+ {
+ to.ErrorCode = validationError.ErrorCode;
+ }
+ if (string.IsNullOrEmpty(to.Message))
+ {
+ to.Message = validationError.ErrorMessage;
+ }
+ }
+ }
+ if (string.IsNullOrEmpty(errorCode))
+ {
+ if (string.IsNullOrEmpty(to.ErrorCode))
+ {
+ throw new ArgumentException("Cannot create a valid error response with a en empty errorCode and an empty validationError list");
+ }
+ }
+ return to;
+ }
+ }
+}
View
47 src/ServiceStack.ServiceInterface/ServiceResponseException.cs
@@ -0,0 +1,47 @@
+using System;
+using ServiceStack.Common.Extensions;
+using ServiceStack.ServiceInterface.ServiceModel;
+
+namespace ServiceStack.ServiceInterface
+{
+ public class ServiceResponseException
+ : Exception
+ {
+ public ServiceResponseException()
+ {
+ }
+
+ public ServiceResponseException(string message)
+ : base(message)
+ {
+ }
+
+ public ServiceResponseException(string errorCode, string errorMessage)
+ : base(GetErrorMessage(errorCode, errorMessage))
+ {
+ this.ErrorCode = errorCode;
+ }
+
+ public ServiceResponseException(string errorCode, string errorMessage, string serviceStackTrace)
+ : base(errorMessage)
+ {
+ this.ErrorCode = errorCode;
+ this.ServiceStackTrace = serviceStackTrace;
+ }
+
+ public ServiceResponseException(ResponseStatus responseStatus)
+ : base(GetErrorMessage(responseStatus.ErrorCode, responseStatus.Message))
+ {
+ this.ErrorCode = responseStatus.ErrorCode;
+ }
+
+ private static string GetErrorMessage(string errorCode, string errorMessage)
+ {
+ return errorMessage ?? (errorCode != null ? errorCode.ToEnglish() : null);
+ }
+
+ public string ErrorCode { get; set; }
+
+ public string ServiceStackTrace { get; set; }
+ }
+}
View
162 src/ServiceStack.ServiceInterface/ServiceStack.ServiceInterface.csproj
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{5A315F92-80D2-4C60-A5A4-22E027AC7E7E}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>ServiceStack.ServiceInterface</RootNamespace>
+ <AssemblyName>ServiceStack.ServiceInterface</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>3.5</OldToolsVersion>
+ <UpgradeBackupLocation />
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'STATIC_ONLY NO_EXPRESSIONS|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\STATIC_ONLY NO_EXPRESSIONS\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Optimize>false</Optimize>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'MonoTouch|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\MonoTouch\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Optimize>false</Optimize>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="ServiceStack">
+ <HintPath>..\ServiceStack\bin\Release\ServiceStack.dll</HintPath>
+ </Reference>
+ <Reference Include="ServiceStack.Common, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\..\lib\ServiceStack.Common.dll</HintPath>
+ </Reference>
+ <Reference Include="ServiceStack.Interfaces, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\ServiceStack.Interfaces\bin\Release\ServiceStack.Interfaces.dll</HintPath>
+ </Reference>
+ <Reference Include="ServiceStack.Text, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\..\lib\ServiceStack.Text.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Runtime.Serialization">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.ServiceModel">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Web" />
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="AsyncServiceBase.cs" />
+ <Compile Include="Config.cs" />
+ <Compile Include="RestServiceBase.cs" />
+ <Compile Include="ServiceBase.cs" />
+ <Compile Include="ServiceModel\ResponseStatusTranslator.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="ServiceResponseException.cs" />
+ <Compile Include="Session\CachedUserSessionManager.cs" />
+ <Compile Include="Session\IUserSessionManager.cs" />
+ <Compile Include="Session\UserClientSession.cs" />
+ <Compile Include="Session\PublicAndPrivateClientSessions.cs" />
+ <Compile Include="Session\UserSession.cs" />
+ <Compile Include="Testing\BasicAppHost.cs" />
+ <Compile Include="Testing\MockHttpRequest.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Testing\TestAppHost.cs" />
+ <Compile Include="Testing\TestBase.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+ <Visible>False</Visible>
+ <ProductName>Windows Installer 3.1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="README.md" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
View
157 src/ServiceStack.ServiceInterface/Session/CachedUserSessionManager.cs
@@ -0,0 +1,157 @@
+/*
+// $Id: CachedUserSessionManager.cs 13365 2010-03-08 18:59:26Z DDNGLOBAL\Demis $
+//
+// Revision : $Revision: 13365 $
+// Modified Date : $LastChangedDate: 2010-03-08 18:59:26 +0000 (Mon, 08 Mar 2010) $
+// Modified By : $LastChangedBy: DDNGLOBAL\Demis $
+//
+// (c) Copyright 2010 Liquidbit Ltd
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using ServiceStack.CacheAccess;
+using ServiceStack.Logging;
+
+namespace ServiceStack.ServiceInterface.Session
+{
+ /// <summary>
+ /// Manages all the User Sessions into the ICacheClient provided
+ /// </summary>
+ public class CachedUserSessionManager
+ : IUserSessionManager
+ {
+ private static readonly ILog Log = LogManager.GetLogger(typeof(CachedUserSessionManager));
+
+ private readonly ICacheClient cacheClient;
+
+ /// <summary>
+ /// Big perf hit if we Log on every session change
+ /// </summary>
+ /// <param name="fmt">The FMT.</param>
+ /// <param name="args">The args.</param>
+ [Conditional("DEBUG")]
+ protected void LogIfDebug(string fmt, params object[] args)
+ {
+ if (args.Length > 0)
+ Log.DebugFormat(fmt, args);
+ else
+ Log.Debug(fmt);
+ }
+
+ public CachedUserSessionManager(ICacheClient cacheClient)
+ {
+ this.cacheClient = cacheClient;
+ }
+
+ /// <summary>
+ /// Removes the client session.
+ /// </summary>
+ /// <param name="userId">The user global id.</param>
+ /// <param name="clientSessionIds">The client session ids.</param>
+ public void RemoveClientSession(Guid userId, ICollection<Guid> clientSessionIds)
+ {
+ var userSession = this.GetUserSession(userId);
+ if (userSession == null) return;
+
+ foreach (var clientSessionId in clientSessionIds)
+ {
+ userSession.RemoveClientSession(clientSessionId);
+ }
+ this.UpdateUserSession(userSession);
+ }
+
+ /// <summary>
+ /// Adds a new client session.
+ /// Should this be changed to GetOrCreateClientSession?
+ /// </summary>
+ /// <param name="userId">The user global id.</param>
+ /// <param name="userName">Title of the user.</param>
+ /// <param name="shardId">The shard id.</param>
+ /// <param name="ipAddress">The ip address.</param>
+ /// <param name="userAgent"></param>
+ /// <param name="base64ClientModulus">The base64 client modulus.</param>
+ /// <param name="userClientGlobalId">The user client global id.</param>
+ /// <returns></returns>
+ public UserClientSession StoreClientSession(Guid userId, string userName, string shardId, string ipAddress, string userAgent, string base64ClientModulus, Guid userClientGlobalId)
+ {
+ var userSession = this.GetOrCreateSession(userId, userName, shardId);
+
+ var existingClientSession = userSession.GetClientSessionWithClientId(userClientGlobalId);
+ if (existingClientSession != null)
+ {
+ userSession.RemoveClientSession(existingClientSession.Id);
+ }
+
+ var newClientSession = userSession.CreateNewClientSession(
+ ipAddress, userAgent, base64ClientModulus, userClientGlobalId);
+
+ this.UpdateUserSession(userSession);
+
+ return newClientSession;
+ }
+
+ /// <summary>
+ /// Updates the UserSession in the cache, or removes expired ones.
+ /// </summary>
+ /// <param name="userSession">The user session.</param>
+ public void UpdateUserSession(UserSession userSession)
+ {
+ var hasSessionExpired = userSession.HasExpired();
+ if (hasSessionExpired)
+ {
+ LogIfDebug("Session has expired, removing: " + userSession.ToCacheKey());
+ this.cacheClient.Remove(userSession.ToCacheKey());
+ }
+ else
+ {
+ LogIfDebug("Updating session: " + userSession.ToCacheKey());
+ this.cacheClient.Replace(userSession.ToCacheKey(), userSession, userSession.ExpiryDate.Value);
+ }
+ }
+
+ /// <summary>
+ /// Gets the user session if it exists or null.
+ /// </summary>
+ /// <param name="userId">The user global id.</param>
+ /// <returns></returns>
+ public UserSession GetUserSession(Guid userId)
+ {
+ var cacheKey = UserSession.ToCacheKey(userId);
+ return this.cacheClient.Get<UserSession>(cacheKey);
+ }
+
+ /// <summary>
+ /// Gets or create a user session if one doesn't exist.
+ /// </summary>
+ /// <param name="userId">The user global id.</param>
+ /// <param name="userName">Title of the user.</param>
+ /// <param name="shardId"></param>
+ /// <returns></returns>
+ public UserSession GetOrCreateSession(Guid userId, string userName, string shardId)
+ {
+ var userSession = this.GetUserSession(userId);
+ if (userSession == null)
+ {
+ userSession = new UserSession(userId, userName, shardId);
+
+ this.cacheClient.Add(userSession.ToCacheKey(), userSession,
+ userSession.ExpiryDate.GetValueOrDefault(DateTime.UtcNow) + TimeSpan.FromHours(1));
+ }
+ return userSession;
+ }
+
+ /// <summary>
+ /// Gets the user client session identified by the id if exists otherwise null.
+ /// </summary>
+ /// <param name="userId">The user global id.</param>
+ /// <param name="clientSessionId">The client session id.</param>
+ /// <returns></returns>
+ public UserClientSession GetUserClientSession(Guid userId, Guid clientSessionId)
+ {
+ var userSession = this.GetUserSession(userId);
+ return userSession != null ? userSession.GetClientSession(clientSessionId) : null;
+ }
+ }
+}
View
80 src/ServiceStack.ServiceInterface/Session/IUserSessionManager.cs
@@ -0,0 +1,80 @@
+/*
+// $Id: IUserSessionManager.cs 13365 2010-03-08 18:59:26Z DDNGLOBAL\Demis $
+//
+// Revision : $Revision: 13365 $
+// Modified Date : $LastChangedDate: 2010-03-08 18:59:26 +0000 (Mon, 08 Mar 2010) $
+// Modified By : $LastChangedBy: DDNGLOBAL\Demis $
+//
+// (c) Copyright 2010 Liquidbit Ltd
+*/
+
+using System;
+using System.Collections.Generic;
+
+namespace ServiceStack.ServiceInterface.Session
+{
+ /// <summary>
+ /// Manager Interface listing all the methods required to manage a users session.
+ /// </summary>
+ public interface IUserSessionManager
+ {
+ /// <summary>
+ /// Removes the client session.
+ /// </summary>
+ /// <param name="userId">The user global id.</param>
+ /// <param name="clientSessionIds">The client session ids.</param>
+ void RemoveClientSession(
+ Guid userId,
+ ICollection<Guid> clientSessionIds);
+
+ /// <summary>
+ /// Adds a new client session.
+ /// </summary>
+ /// <param name="userId">The user global id.</param>
+ /// <param name="userName">Title of the user.</param>
+ /// <param name="shardId">The shard id.</param>
+ /// <param name="ipAddress">The ip address.</param>
+ /// <param name="userAgent">The user agent.</param>
+ /// <param name="base64ClientModulus">The base64 client modulus.</param>
+ /// <param name="userClientGlobalId">The user client global id.</param>
+ /// <returns></returns>
+ UserClientSession StoreClientSession(
+ Guid userId,
+ string userName,
+ string shardId,
+ string ipAddress,
+ string userAgent,
+ string base64ClientModulus,
+ Guid userClientGlobalId);
+
+ /// <summary>
+ /// Updates the UserSession in the cache, or removes expired ones.
+ /// </summary>
+ /// <param name="userSession">The user session.</param>
+ void UpdateUserSession(UserSession userSession);
+
+ /// <summary>
+ /// Gets the user session if it exists or null.
+ /// </summary>
+ /// <param name="userId">The user global id.</param>
+ /// <returns></returns>
+ UserSession GetUserSession(Guid userId);
+
+ /// <summary>
+ /// Gets or create a user session if one doesn't exist.
+ /// </summary>
+ /// <param name="userId">The user global id.</param>
+ /// <param name="userName">Title of the user.</param>
+ /// <param name="shardId"></param>
+ /// <returns></returns>
+ UserSession GetOrCreateSession(Guid userId, string userName, string shardId);
+
+ /// <summary>
+ /// Gets the user client session identified by the id if exists otherwise null.
+ /// </summary>
+ /// <param name="userId">The user global id.</param>
+ /// <param name="clientSessionId">The client session id.</param>
+ /// <returns></returns>
+ UserClientSession GetUserClientSession(Guid userId, Guid clientSessionId);
+ }
+}
View
30 src/ServiceStack.ServiceInterface/Session/PublicAndPrivateClientSessions.cs
@@ -0,0 +1,30 @@
+/*
+// $Id: PublicAndPrivateClientSessions.cs 3595 2009-05-20 09:57:17Z Demis Bellot $
+//
+// Revision : $Revision: 3595 $
+// Modified Date : $LastChangedDate: 2009-05-20 10:57:17 +0100 (Wed, 20 May 2009) $
+// Modified By : $LastChangedBy: Demis Bellot $
+//
+// (c) Copyright 2010 Liquidbit Ltd
+*/
+
+
+namespace ServiceStack.ServiceInterface.Session
+{
+ /// <summary>
+ /// Holds a 'Secure' and 'Unsecure' client session for the user.
+ /// The secure client session should only be transported over a secure channel.
+ /// </summary>
+ public class PublicAndPrivateClientSessions
+ {
+ public PublicAndPrivateClientSessions(
+ UserClientSession unsecureClientSession, UserClientSession secureClientSession)
+ {
+ this.UnsecureClientSession = unsecureClientSession;
+ this.SecureClientSession = secureClientSession;
+ }
+
+ public UserClientSession UnsecureClientSession { get; private set; }
+ public UserClientSession SecureClientSession { get; private set; }
+ }
+}
View
86 src/ServiceStack.ServiceInterface/Session/UserClientSession.cs
@@ -0,0 +1,86 @@
+/*
+// $Id: UserClientSession.cs 13369 2010-03-08 19:09:44Z DDNGLOBAL\Demis $
+//
+// Revision : $Revision: 13369 $
+// Modified Date : $LastChangedDate: 2010-03-08 19:09:44 +0000 (Mon, 08 Mar 2010) $
+// Modified By : $LastChangedBy: DDNGLOBAL\Demis $
+//
+// (c) Copyright 2010 Liquidbit Ltd
+*/
+
+using System;
+using ServiceStack.DesignPatterns.Model;
+
+namespace ServiceStack.ServiceInterface.Session
+{
+ /// <summary>
+ /// Holds information on a single 'User Client' session.
+ ///
+ /// A user can have multiple of these client sessions,
+ /// each from a different web browser or client application.
+ /// </summary>
+ public class UserClientSession
+ : IHasGuidId
+ {
+ private const int ValidForTwoWeeks = 14;
+
+ /// <summary>
+ /// Unique Id for this session
+ /// </summary>
+ public Guid Id { get; set; }
+
+ /// <summary>
+ /// Id of the User for this session
+ /// </summary>
+ public Guid UserId { get; set; }
+
+ /// <summary>
+ /// If provided stores the clients public key to enable secure transmission
+ /// </summary>
+ public string Base64ClientModulus { get; set; }
+
+ /// <summary>
+ /// The unique global and persistent id for the client application.
+ /// (Can be stored in a persistent cookie)
+ /// </summary>
+ public Guid UserClientGlobalId { get; set; }
+
+ /// <summary>
+ /// The IpAddress for the client
+ /// </summary>
+ public string IpAddress { get; private set; }
+
+ /// <summary>
+ /// Holds meta-information about the operating environment of this client
+ /// </summary>
+ public string UserAgent { get; private set; }
+
+ /// <summary>
+ /// When this client session expires
+ /// </summary>
+ public DateTime ExpiryDate { get; set; }
+
+ /// <summary>
+ /// Empty constructor required for TypeSerializer
+ /// </summary>
+ public UserClientSession() {}
+
+ public UserClientSession(
+ Guid sessionId,
+ Guid userId,
+ string ipAddress,
+ string userAgent,
+ string base64ClientModulus,
+ Guid userClientGlobalId)
+ {
+ this.Id = sessionId;
+ this.UserId = userId;
+ this.IpAddress = ipAddress;
+ this.UserAgent = userAgent;
+ this.Base64ClientModulus = base64ClientModulus;
+ this.UserClientGlobalId = userClientGlobalId;
+ this.ExpiryDate = DateTime.UtcNow.AddDays(ValidForTwoWeeks);
+ }
+ }
+
+}
View
174 src/ServiceStack.ServiceInterface/Session/UserSession.cs
@@ -0,0 +1,174 @@
+/*
+// $Id: UserSession.cs 13369 2010-03-08 19:09:44Z DDNGLOBAL\Demis $
+//
+// Revision : $Revision: 13369 $
+// Modified Date : $LastChangedDate: 2010-03-08 19:09:44 +0000 (Mon, 08 Mar 2010) $
+// Modified By : $LastChangedBy: DDNGLOBAL\Demis $
+//
+// (c) Copyright 2010 Liquidbit Ltd
+*/
+
+using System;
+using System.Collections.Generic;
+using ServiceStack.Common;
+
+namespace ServiceStack.ServiceInterface.Session
+{
+ /// <summary>
+ /// Holds all the data required for a User Session
+ /// </summary>
+ public class UserSession
+ {
+ //Empty constructor required for TypeSerializer
+ public UserSession()
+ {
+ this.PublicClientSessions = new Dictionary<Guid, UserClientSession>();
+ }
+
+ public Guid UserId { get; private set; }
+
+ public string UserName { get; private set; }
+
+ public string ShardId { get; private set; }
+
+ public Dictionary<Guid, UserClientSession> PublicClientSessions { get; private set; }
+
+ public UserSession(Guid userId, string userName, string shardId)
+ : this()
+ {
+ this.UserId = userId;
+ this.UserName = userName;
+ this.ShardId = shardId;
+ }
+
+ /// <summary>
+ /// Gets the max expiry date of all the users client sessions.
+ /// If the user has no more active client sessions we can remove them from the cache.
+ /// </summary>
+ /// <value>The expiry date.</value>
+ public DateTime? ExpiryDate
+ {
+ get
+ {
+ DateTime? maxExpiryDate = null;
+
+ foreach (var session in this.PublicClientSessions.Values)
+ {
+ if (maxExpiryDate == null || session.ExpiryDate > maxExpiryDate)
+ {
+ maxExpiryDate = session.ExpiryDate;
+ }
+ }
+ return maxExpiryDate;
+ }
+ }
+
+ /// <summary>
+ /// Creates a new client session for the user.
+ /// </summary>
+ /// <param name="ipAddress">The ip address.</param>
+ /// <param name="userAgent">The user agent.</param>
+ /// <param name="base64ClientModulus">The base64 client modulus.</param>
+ /// <param name="userClientGlobalId">The user client global id.</param>
+ /// <returns></returns>
+ public UserClientSession CreateNewClientSession(string ipAddress, string userAgent, string base64ClientModulus, Guid userClientGlobalId)
+ {
+ return this.CreateClientSession(Guid.NewGuid(), ipAddress, userAgent, base64ClientModulus, userClientGlobalId);
+ }
+
+ public UserClientSession CreateClientSession(Guid sessionId, string ipAddress, string userAgent, string base64ClientModulus, Guid userClientGlobalId)
+ {
+ var clientSession = new UserClientSession(
+ sessionId, this.UserId, ipAddress, userAgent, base64ClientModulus, userClientGlobalId);
+
+ this.PublicClientSessions[clientSession.Id] = clientSession;
+
+ return clientSession;
+ }
+
+ /// <summary>
+ /// Removes the client session.
+ /// </summary>
+ /// <param name="clientSessionId">The client session id.</param>
+ public void RemoveClientSession(Guid clientSessionId)
+ {
+ if (this.PublicClientSessions.ContainsKey(clientSessionId))
+ {
+ this.PublicClientSessions.Remove(clientSessionId);
+ }
+ }
+
+ public UserClientSession GetClientSessionWithClientId(Guid userClientId)
+ {
+ foreach (var entry in this.PublicClientSessions)
+ {
+ if (entry.Value.UserClientGlobalId == userClientId)
+ {
+ return entry.Value;
+ }
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Verifies this UserSession, removing any expired sessions.
+ /// Returns true to keep the UserSession in the cache.
+ /// </summary>
+ /// <returns>
+ /// <c>true</c> if this session has any active client sessions; otherwise, <c>false</c>.
+ /// </returns>
+ public bool HasExpired()
+ {
+ RemoveExpiredSessions(this.PublicClientSessions);
+
+ //If there are no more active client sessions we can remove the entire UserSession
+ var sessionHasExpired =
+ this.ExpiryDate == null //There are no UserClientSessions
+ || this.ExpiryDate.Value <= DateTime.UtcNow; //The max UserClientSession ExpiryDate has expired
+
+ return sessionHasExpired;
+ }
+
+ private static void RemoveExpiredSessions(IDictionary<Guid, UserClientSession> clientSessions)
+ {
+ var expiredSessionKeys = new List<Guid>();
+
+ foreach (var clientSession in clientSessions)
+ {
+ if (clientSession.Value.ExpiryDate < DateTime.UtcNow)
+ {
+ expiredSessionKeys.Add(clientSession.Key);
+ }
+ }
+
+ foreach (var sessionKey in expiredSessionKeys)
+ {
+ clientSessions.Remove(sessionKey);
+ }
+ }
+
+ public void RemoveAllSessions()
+ {
+ this.PublicClientSessions.Clear();
+ }
+
+ public UserClientSession GetClientSession(Guid clientSessionId)
+ {
+ UserClientSession session;
+
+ return this.PublicClientSessions.TryGetValue(clientSessionId, out session)
+ ? session : null;
+ }
+
+ public string ToCacheKey()
+ {
+ return ToCacheKey(this.UserId);
+ }
+
+ public static string ToCacheKey(Guid userId)
+ {
+ return UrnId.Create<UserSession>(userId.ToString());
+ }
+ }
+}
View
39 src/ServiceStack.ServiceInterface/Testing/BasicAppHost.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using Funq;
+using ServiceStack.ServiceHost;
+using ServiceStack.WebHost.Endpoints;
+
+namespace ServiceStack.ServiceInterface.Testing
+{
+ public class BasicAppHost : IAppHost
+ {
+ public BasicAppHost()
+ {
+ this.Container = new Container();
+ this.RequestFilters = new List<Action<IHttpRequest, IHttpResponse, object>>();
+ this.ResponseFilters = new List<Action<IHttpRequest, IHttpResponse, object>>();
+ this.HtmlProviders = new List<StreamSerializerResolverDelegate>();
+ this.CatchAllHandlers = new List<HttpHandlerResolverDelegate>();
+ }
+
+ public T TryResolve<T>()
+ {
+ return this.Container.TryResolve<T>();
+ }
+
+ public Container Container { get; set; }
+
+ public IContentTypeFilter ContentTypeFilters { get; set; }
+
+ public List<Action<IHttpRequest, IHttpResponse, object>> RequestFilters { get; set; }
+
+ public List<Action<IHttpRequest, IHttpResponse, object>> ResponseFilters { get; set; }
+
+ public List<StreamSerializerResolverDelegate> HtmlProviders { get; set; }
+
+ public List<HttpHandlerResolverDelegate> CatchAllHandlers { get; set; }
+
+ public EndpointHostConfig Config { get; set; }
+ }
+}
View
98 src/ServiceStack.ServiceInterface/Testing/MockHttpRequest.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.IO;
+using System.Net;
+using ServiceStack.ServiceHost;
+
+namespace ServiceStack.ServiceInterface.Testing
+{
+ public class MockHttpRequest : IHttpRequest
+ {
+ public MockHttpRequest()
+ {
+ this.FormData = new NameValueCollection();
+ this.Headers = new NameValueCollection();
+ this.Cookies = new Dictionary<string, Cookie>();
+ this.Items = new Dictionary<string, object>();
+ }
+
+ public MockHttpRequest(string operationName, string httpMethod,
+ string contentType, string pathInfo,
+ NameValueCollection queryString, Stream inputStream, NameValueCollection formData)
+ : this()
+ {
+ this.OperationName = operationName;
+ this.HttpMethod = httpMethod;
+ this.ContentType = contentType;
+ this.ResponseContentType = contentType;
+ this.PathInfo = pathInfo;
+ this.InputStream = inputStream;
+ this.QueryString = queryString;
+ this.FormData = formData ?? new NameValueCollection();
+ }
+
+ public string OperationName { get; set; }
+ public string ContentType { get; set; }
+ public string HttpMethod { get; set; }
+
+ public IDictionary<string, Cookie> Cookies { get; set; }
+
+ private string responseContentType;
+ public string ResponseContentType
+ {
+ get { return responseContentType ?? this.ContentType; }
+ set { responseContentType = value; }
+ }
+
+ public NameValueCollection Headers { get; set; }
+
+ public NameValueCollection QueryString { get; set; }
+
+ public NameValueCollection FormData { get; set; }
+
+ public Dictionary<string, object> Items
+ {
+ get;
+ private set;
+ }
+
+ private string rawBody;
+ public string GetRawBody()
+ {
+ if (rawBody != null) return rawBody;
+ if (InputStream == null) return null;
+
+ //Keep the stream alive in-case it needs to be read twice (i.e. ContentLength)
+ rawBody = new StreamReader(InputStream).ReadToEnd();
+ InputStream.Position = 0;
+ return rawBody;
+ }
+
+ public string RawUrl { get; set; }
+
+ public string AbsoluteUri
+ {
+ get { return "http://localhost" + this.PathInfo; }
+ }
+
+ public string UserHostAddress { get; set; }
+ public bool IsSecureConnection { get; set; }
+ public string[] AcceptTypes { get; set; }
+ public string PathInfo { get; set; }
+ public Stream InputStream { get; set; }
+
+ public long ContentLength
+ {
+ get
+ {
+ var body = GetRawBody();
+ return body != null ? body.Length : 0;
+ }
+ }
+
+ public IFile[] Files { get; set; }
+
+ public string ApplicationFilePath { get; set; }
+ }
+}
View
54 src/ServiceStack.ServiceInterface/Testing/TestAppHost.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Funq;
+using ServiceStack.Common.Web;
+using ServiceStack.ServiceHost;
+using ServiceStack.WebHost.Endpoints;
+
+namespace ServiceStack.ServiceInterface.Testing
+{
+ public class TestAppHost : IAppHost
+ {
+ private readonly Funq.Container container;
+
+ public TestAppHost()
+ : this(new Container(), Assembly.GetExecutingAssembly()) {}
+
+ public TestAppHost(Funq.Container container, params Assembly[] serviceAssemblies)
+ {
+ this.container = container ?? new Container();
+ if (serviceAssemblies.Length == 0)
+ serviceAssemblies = new[] { Assembly.GetExecutingAssembly() };
+
+ var createInstance = EndpointHostConfig.Instance;
+
+ this.Config = EndpointHost.Config = new EndpointHostConfig {
+ ServiceName = GetType().Name,
+ ServiceManager = new ServiceManager(true, serviceAssemblies),
+ };
+ this.ContentTypeFilters = new HttpResponseFilter();
+ this.RequestFilters = new List<Action<IHttpRequest, IHttpResponse, object>>();
+ this.ResponseFilters = new List<Action<IHttpRequest, IHttpResponse, object>>();
+ this.HtmlProviders = new List<StreamSerializerResolverDelegate>();
+ this.CatchAllHandlers = new List<HttpHandlerResolverDelegate>();
+ }
+
+ public T TryResolve<T>()
+ {
+ return container.TryResolve<T>();
+ }
+
+ public IContentTypeFilter ContentTypeFilters { get; set; }
+
+ public List<Action<IHttpRequest, IHttpResponse, object>> RequestFilters { get; set; }
+
+ public List<Action<IHttpRequest, IHttpResponse, object>> ResponseFilters { get; set; }
+
+ public List<StreamSerializerResolverDelegate> HtmlProviders { get; private set; }
+
+ public List<HttpHandlerResolverDelegate> CatchAllHandlers { get; private set; }
+
+ public EndpointHostConfig Config { get; set; }
+ }
+}
View
394 src/ServiceStack.ServiceInterface/Testing/TestBase.cs
@@ -0,0 +1,394 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Reflection;
+using System.Text;
+using Funq;
+using ServiceStack.Common;
+using ServiceStack.Common.Utils;
+using ServiceStack.Common.Web;
+using ServiceStack.Service;
+using ServiceStack.ServiceClient.Web;
+using ServiceStack.ServiceHost;
+using ServiceStack.ServiceInterface.ServiceModel;
+using ServiceStack.ServiceModel;
+using ServiceStack.Text;
+using ServiceStack.WebHost.Endpoints;
+using ServiceStack.WebHost.Endpoints.Support;
+
+namespace ServiceStack.ServiceInterface.Testing
+{
+ public abstract class TestBase
+ {
+ protected IAppHost AppHost { get; set; }
+
+ protected bool HasConfigured { get; set; }
+
+ protected TestBase(params Assembly[] serviceAssemblies)
+ : this(null, serviceAssemblies) { }
+
+ protected TestBase(string serviceClientBaseUri, params Assembly[] serviceAssemblies)
+ {
+ if (serviceAssemblies.Length == 0)
+ serviceAssemblies = new[] { GetType().Assembly };
+
+ ServiceClientBaseUri = serviceClientBaseUri;
+ ServiceAssemblies = serviceAssemblies;
+
+ var serviceManager = new ServiceManager(serviceAssemblies);
+
+ this.AppHost = new TestAppHost(serviceManager.Container, serviceAssemblies);
+
+ EndpointHost.ConfigureHost(this.AppHost, "TestBase", serviceManager);
+
+ EndpointHost.ServiceManager = this.AppHost.Config.ServiceManager;
+ }
+
+ protected abstract void Configure(Funq.Container container);
+
+ protected Funq.Container Container
+ {
+ get { return EndpointHost.ServiceManager.Container; }
+ }
+
+ protected IServiceRoutes Routes
+ {
+ get { return EndpointHost.ServiceManager.ServiceController.Routes; }
+ }
+
+ //All integration tests call the Webservices hosted at the following location:
+ protected string ServiceClientBaseUri { get; set; }
+ protected Assembly[] ServiceAssemblies { get; set; }
+
+ public virtual void OnBeforeTestFixture()
+ {
+ OnConfigure();
+ }
+
+ protected virtual void OnConfigure()
+ {
+ if (HasConfigured) return;
+
+ HasConfigured = true;
+ Configure(Container);
+ EndpointHost.AfterInit();
+ }
+
+ public virtual void OnBeforeEachTest()
+ {
+ OnConfigure();
+ }
+
+ protected virtual IServiceClient CreateNewServiceClient()
+ {
+ return new DirectServiceClient(this, EndpointHost.ServiceManager);
+ }
+
+ protected virtual IRestClient CreateNewRestClient()
+ {
+ return new DirectServiceClient(this, EndpointHost.ServiceManager);
+ }
+
+ protected virtual IRestClientAsync CreateNewRestClientAsync()
+ {
+ return new DirectServiceClient(this, EndpointHost.ServiceManager);
+ }
+
+ public class DirectServiceClient : IServiceClient, IRestClient
+ {
+ private readonly TestBase parent;
+ ServiceManager ServiceManager { get; set; }
+
+ public DirectServiceClient(TestBase parent, ServiceManager serviceManager)
+ {
+ this.parent = parent;
+ this.ServiceManager = serviceManager;
+ }
+
+ public void SendOneWay(object request)
+ {
+ ServiceManager.Execute(request);
+ }
+
+ public TResponse Send<TResponse>(object request)
+ {
+ var response = ServiceManager.Execute(request);
+ return (TResponse)response;
+ }
+
+ public TResponse Get<TResponse>(string relativeOrAbsoluteUrl)
+ {
+ return parent.ExecutePath<TResponse>(HttpMethod.Get, new UrlParts(relativeOrAbsoluteUrl), null);
+ }
+
+ public TResponse Delete<TResponse>(string relativeOrAbsoluteUrl)
+ {
+ return parent.ExecutePath<TResponse>(HttpMethod.Delete, new UrlParts(relativeOrAbsoluteUrl), null);
+ }
+
+ public TResponse Post<TResponse>(string relativeOrAbsoluteUrl, object request)
+ {
+ return parent.ExecutePath<TResponse>(HttpMethod.Post, new UrlParts(relativeOrAbsoluteUrl), request);
+ }
+
+ public TResponse Put<TResponse>(string relativeOrAbsoluteUrl, object request)
+ {
+ return parent.ExecutePath<TResponse>(HttpMethod.Put, new UrlParts(relativeOrAbsoluteUrl), request);
+ }
+
+ public TResponse PostFile<TResponse>(string relativeOrAbsoluteUrl, FileInfo fileToUpload, string mimeType)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void SendAsync<TResponse>(object request,
+ Action<TResponse> onSuccess, Action<TResponse, Exception> onError)
+ {
+ try
+ {
+ var response = (TResponse)ServiceManager.Execute(request);
+ onSuccess(response);
+ }
+ catch (Exception ex)
+ {
+ HandleException(ex, onError);
+ }
+ }
+
+ private static void HandleException<TResponse>(Exception exception, Action<TResponse, Exception> onError)
+ {
+ var response = (TResponse)ReflectionUtils.CreateInstance(typeof(TResponse));
+ var hasResponseStatus = response as IHasResponseStatus;
+ if (hasResponseStatus != null)
+ {
+ hasResponseStatus.ResponseStatus = new ResponseStatus {
+ ErrorCode = exception.GetType().Name,
+ Message = exception.Message,
+ StackTrace = exception.StackTrace,
+ };
+ }
+ var webServiceEx = new WebServiceException(exception.Message, exception);
+ if (onError != null) onError(response, webServiceEx);
+ }
+
+ public void SetCredentials(string userName, string password)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void GetAsync<TResponse>(string relativeOrAbsoluteUrl, Action<TResponse> onSuccess, Action<TResponse, Exception> onError)
+ {
+ try
+ {
+ var response = parent.ExecutePath<TResponse>(HttpMethod.Get, new UrlParts(relativeOrAbsoluteUrl), default(TResponse));
+ onSuccess(response);
+ }
+ catch (Exception ex)
+ {
+ HandleException(ex, onError);
+ }
+ }
+
+ public void DeleteAsync<TResponse>(string relativeOrAbsoluteUrl, Action<TResponse> onSuccess, Action<TResponse, Exception> onError)
+ {
+ try
+ {
+ var response = parent.ExecutePath<TResponse>(HttpMethod.Delete, new UrlParts(relativeOrAbsoluteUrl), default(TResponse));
+ onSuccess(response);
+ }
+ catch (Exception ex)
+ {
+ HandleException(ex, onError);
+ }
+ }
+
+ public void PostAsync<TResponse>(string relativeOrAbsoluteUrl, object request, Action<TResponse> onSuccess, Action<TResponse, Exception> onError)
+ {
+ try
+ {
+ var response = parent.ExecutePath<TResponse>(HttpMethod.Post, new UrlParts(relativeOrAbsoluteUrl), request);
+ onSuccess(response);
+ }
+ catch (Exception ex)
+ {
+ HandleException(ex, onError);
+ }
+ }
+
+ public void PutAsync<TResponse>(string relativeOrAbsoluteUrl, object request, Action<TResponse> onSuccess, Action<TResponse, Exception> onError)
+ {
+ try
+ {
+ var response = parent.ExecutePath<TResponse>(HttpMethod.Put, new UrlParts(relativeOrAbsoluteUrl), request);
+ onSuccess(response);
+ }
+ catch (Exception ex)
+ {
+ HandleException(ex, onError);
+ }
+ }
+
+ public void Dispose() { }
+ }
+
+ public object ExecutePath(string pathInfo)
+ {
+ return ExecutePath(HttpMethods.Get, pathInfo);
+ }
+
+ private class UrlParts
+ {
+ public UrlParts(string pathInfo)
+ {
+ this.PathInfo = pathInfo.UrlDecode();
+ var qsIndex = pathInfo.IndexOf("?");
+ if (qsIndex != -1)
+ {
+ var qs = pathInfo.Substring(qsIndex + 1);
+ this.PathInfo = pathInfo.Substring(0, qsIndex);
+ var kvps = qs.Split('&');
+
+ this.QueryString = new Dictionary<string, string>();
+ foreach (var kvp in kvps)
+ {
+ var parts = kvp.Split('=');
+ this.QueryString[parts[0]] = parts.Length > 1 ? parts[1] : null;
+ }
+ }
+ }
+
+ public string PathInfo { get; private set; }
+ public Dictionary<string, string> QueryString { get; private set; }
+ }
+
+ public object ExecutePath(string httpMethod, string pathInfo)
+ {
+ var urlParts = new UrlParts(pathInfo);
+ return ExecutePath(httpMethod, urlParts.PathInfo, urlParts.QueryString, null, null);
+ }
+
+ private TResponse ExecutePath<TResponse>(string httpMethod, UrlParts urlParts, object requestDto)
+ {
+ return (TResponse)ExecutePath(httpMethod, urlParts.PathInfo, urlParts.QueryString, null, requestDto);
+ }
+
+ public TResponse ExecutePath<TResponse>(string httpMethod, string pathInfo, object requestDto)
+ {
+ var urlParts = new UrlParts(pathInfo);
+ return (TResponse)ExecutePath(httpMethod, urlParts.PathInfo, urlParts.QueryString, null, requestDto);
+ }
+
+ public object ExecutePath<T>(
+ string httpMethod,
+ string pathInfo,
+ Dictionary<string, string> queryString,
+ Dictionary<string, string> formData,
+ T requestBody)
+ {
+ var isDefault = Equals(requestBody, default(T));
+ var json = !isDefault ? JsonSerializer.SerializeToString(requestBody) : null;
+ return ExecutePath(httpMethod, pathInfo, queryString, formData, json);
+ }
+
+ public object ExecutePath(
+ string httpMethod,
+ string pathInfo,
+ Dictionary<string, string> queryString,
+ Dictionary<string, string> formData,
+ string requestBody)
+ {
+ var httpHandler = GetHandler(httpMethod, pathInfo);
+
+ var contentType = (formData != null && formData.Count > 0)
+ ? ContentType.FormUrlEncoded
+ : requestBody != null ? ContentType.Json : null;
+
+ var httpReq = new MockHttpRequest(
+ httpHandler.RequestName, httpMethod, contentType,
+ pathInfo,
+ queryString.ToNameValueCollection(),
+ requestBody == null ? null : new MemoryStream(Encoding.UTF8.GetBytes(requestBody)),
+ formData.ToNameValueCollection()
+ );
+
+ var request = httpHandler.CreateRequest(httpReq, httpHandler.RequestName);
+ var response = httpHandler.GetResponse(httpReq, request);
+
+ var httpRes = response as IHttpResult;
+ if (httpRes != null)
+ {
+ var httpError = httpRes as IHttpError;
+ if (httpError != null)
+ {
+ throw new WebServiceException(httpError.Message) {
+ StatusCode = (int)httpError.StatusCode,
+ ResponseDto = httpError.Response
+ };
+ }
+ var hasResponseStatus = httpRes.Response as IHasResponseStatus;
+ if (hasResponseStatus != null)
+ {
+ var status = hasResponseStatus.ResponseStatus;
+ if (status != null && !status.ErrorCode.IsNullOrEmpty())
+ {
+ throw new WebServiceException(status.Message) {
+ StatusCode = (int)HttpStatusCode.InternalServerError,
+ ResponseDto = httpRes.Response,
+ };
+ }
+ }
+
+ return httpRes.Response;
+ }
+
+ return response;
+ }
+
+ public object GetRequest(string pathInfo)
+ {
+ var urlParts = new UrlParts(pathInfo);
+ return GetRequest(HttpMethods.Get, urlParts.PathInfo, urlParts.QueryString, null, null);
+ }
+
+ public object GetRequest(string httpMethod, string pathInfo)
+ {
+ var urlParts = new UrlParts(pathInfo);
+ return GetRequest(httpMethod, urlParts.PathInfo, urlParts.QueryString, null, null);
+ }
+
+ public object GetRequest(
+ string httpMethod,
+ string pathInfo,
+ Dictionary<string, string> queryString,
+ Dictionary<string, string> formData,
+ string requestBody)
+ {
+ var httpHandler = GetHandler(httpMethod, pathInfo);
+
+ var contentType = (formData != null && formData.Count > 0)
+ ? ContentType.FormUrlEncoded
+ : requestBody != null ? ContentType.Json : null;
+
+ var httpReq = new MockHttpRequest(
+ httpHandler.RequestName, httpMethod, contentType,
+ pathInfo,
+ queryString.ToNameValueCollection(),
+ requestBody == null ? null : new MemoryStream(Encoding.UTF8.GetBytes(requestBody)),
+ formData.ToNameValueCollection()
+ );
+
+ var request = httpHandler.CreateRequest(httpReq, httpHandler.RequestName);
+ return request;
+ }
+
+ private static EndpointHandlerBase GetHandler(string httpMethod, string pathInfo)
+ {
+ var httpHandler = ServiceStackHttpHandlerFactory.GetHandlerForPathInfo(httpMethod, pathInfo, pathInfo, null) as EndpointHandlerBase;
+ if (httpHandler == null)
+ throw new NotSupportedException(pathInfo);
+ return httpHandler;
+ }
+ }
+
+}
View
33 src/ServiceStack.sln
@@ -29,69 +29,102 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceStack.WebHost.Integr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterHost", "..\tests\MasterHost\MasterHost.csproj", "{12FA52E0-E648-42B3-9F67-782011AD20C4}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceStack.ServiceInterface", "ServiceStack.ServiceInterface\ServiceStack.ServiceInterface.csproj", "{5A315F92-80D2-4C60-A5A4-22E027AC7E7E}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
MonoTouch|Any CPU = MonoTouch|Any CPU
Release|Any CPU = Release|Any CPU
+ STATIC_ONLY NO_EXPRESSIONS|Any CPU = STATIC_ONLY NO_EXPRESSIONS|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{680A1709-25EB-4D52-A87F-EE03FFD94BAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{680A1709-25EB-4D52-A87F-EE03FFD94BAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{680A1709-25EB-4D52-A87F-EE03FFD94BAA}.MonoTouch|Any CPU.ActiveCfg = DEBUG MONO|Any CPU
{680A1709-25EB-4D52-A87F-EE03FFD94BAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{680A1709-25EB-4D52-A87F-EE03FFD94BAA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {680A1709-25EB-4D52-A87F-EE03FFD94BAA}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = DEBUG MONO|Any CPU
+ {680A1709-25EB-4D52-A87F-EE03FFD94BAA}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = DEBUG MONO|Any CPU
{982416DB-C143-4028-A0C3-CF41892D18D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{982416DB-C143-4028-A0C3-CF41892D18D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{982416DB-C143-4028-A0C3-CF41892D18D3}.MonoTouch|Any CPU.ActiveCfg = MonoTouch|Any CPU
{982416DB-C143-4028-A0C3-CF41892D18D3}.MonoTouch|Any CPU.Build.0 = MonoTouch|Any CPU
{982416DB-C143-4028-A0C3-CF41892D18D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{982416DB-C143-4028-A0C3-CF41892D18D3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {982416DB-C143-4028-A0C3-CF41892D18D3}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = STATIC_ONLY NO_EXPRESSIONS|Any CPU
+ {982416DB-C143-4028-A0C3-CF41892D18D3}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = STATIC_ONLY NO_EXPRESSIONS|Any CPU
{6B133D45-91D4-4AA5-A6D4-247282879CBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6B133D45-91D4-4AA5-A6D4-247282879CBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B133D45-91D4-4AA5-A6D4-247282879CBB}.MonoTouch|Any CPU.ActiveCfg = MonoTouch|Any CPU
{6B133D45-91D4-4AA5-A6D4-247282879CBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B133D45-91D4-4AA5-A6D4-247282879CBB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6B133D45-91D4-4AA5-A6D4-247282879CBB}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = STATIC_ONLY NO_EXPRESSIONS|Any CPU
+ {6B133D45-91D4-4AA5-A6D4-247282879CBB}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = STATIC_ONLY NO_EXPRESSIONS|Any CPU
{3FA9197A-462D-44CC-9AB3-61AF414D0B45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3FA9197A-462D-44CC-9AB3-61AF414D0B45}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3FA9197A-462D-44CC-9AB3-61AF414D0B45}.MonoTouch|Any CPU.ActiveCfg = MonoTouch|Any CPU
{3FA9197A-462D-44CC-9AB3-61AF414D0B45}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3FA9197A-462D-44CC-9AB3-61AF414D0B45}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3FA9197A-462D-44CC-9AB3-61AF414D0B45}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = STATIC_ONLY NO_EXPRESSIONS|Any CPU
+ {3FA9197A-462D-44CC-9AB3-61AF414D0B45}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = STATIC_ONLY NO_EXPRESSIONS|Any CPU
{CA20892F-3FD7-4ACD-8506-B50C30CA4DE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CA20892F-3FD7-4ACD-8506-B50C30CA4DE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CA20892F-3FD7-4ACD-8506-B50C30CA4DE1}.MonoTouch|Any CPU.ActiveCfg = MonoTouch|Any CPU
{CA20892F-3FD7-4ACD-8506-B50C30CA4DE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CA20892F-3FD7-4ACD-8506-B50C30CA4DE1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CA20892F-3FD7-4ACD-8506-B50C30CA4DE1}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = STATIC_ONLY NO_EXPRESSIONS|Any CPU
+ {CA20892F-3FD7-4ACD-8506-B50C30CA4DE1}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = STATIC_ONLY NO_EXPRESSIONS|Any CPU
{94A33BC4-AC22-49A3-A38E-2ABFCD997ABA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{94A33BC4-AC22-49A3-A38E-2ABFCD997ABA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{94A33BC4-AC22-49A3-A38E-2ABFCD997ABA}.MonoTouch|Any CPU.ActiveCfg = MonoTouch|Any CPU
{94A33BC4-AC22-49A3-A38E-2ABFCD997ABA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{94A33BC4-AC22-49A3-A38E-2ABFCD997ABA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {94A33BC4-AC22-49A3-A38E-2ABFCD997ABA}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = STATIC_ONLY NO_EXPRESSIONS|Any CPU
+ {94A33BC4-AC22-49A3-A38E-2ABFCD997ABA}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = STATIC_ONLY NO_EXPRESSIONS|Any CPU
{A5646013-C243-453F-A2B6-3B6870A9637D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5646013-C243-453F-A2B6-3B6870A9637D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5646013-C243-453F-A2B6-3B6870A9637D}.MonoTouch|Any CPU.ActiveCfg = MonoTouch|Any CPU
{A5646013-C243-453F-A2B6-3B6870A9637D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5646013-C243-453F-A2B6-3B6870A9637D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A5646013-C243-453F-A2B6-3B6870A9637D}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = STATIC_ONLY NO_EXPRESSIONS|Any CPU
+ {A5646013-C243-453F-A2B6-3B6870A9637D}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = STATIC_ONLY NO_EXPRESSIONS|Any CPU
{55C5C6DA-1834-4BA8-8D2F-19C091B6FC81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{55C5C6DA-1834-4BA8-8D2F-19C091B6FC81}.Debug|Any CPU.Build.0 = Debug|Any CPU
{55C5C6DA-1834-4BA8-8D2F-19C091B6FC81}.MonoTouch|Any CPU.ActiveCfg = MonoTouch|Any CPU
{55C5C6DA-1834-4BA8-8D2F-19C091B6FC81}.Release|Any CPU.ActiveCfg = Release|Any CPU
{55C5C6DA-1834-4BA8-8D2F-19C091B6FC81}.Release|Any CPU.Build.0 = Release|Any CPU
+ {55C5C6DA-1834-4BA8-8D2F-19C091B6FC81}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = STATIC_ONLY NO_EXPRESSIONS|Any CPU
+ {55C5C6DA-1834-4BA8-8D2F-19C091B6FC81}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = STATIC_ONLY NO_EXPRESSIONS|Any CPU
{42E1C8C0-A163-44CC-92B1-8F416F2C0B01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{42E1C8C0-A163-44CC-92B1-8F416F2C0B01}.Debug|Any CPU.Build.0 = Debug|Any CPU
{42E1C8C0-A163-44CC-92B1-8F416F2C0B01}.MonoTouch|Any CPU.ActiveCfg = Release|Any CPU
{42E1C8C0-A163-44CC-92B1-8F416F2C0B01}.Release|Any CPU.ActiveCfg = Release|Any CPU
{42E1C8C0-A163-44CC-92B1-8F416F2C0B01}.Release|Any CPU.Build.0 = Release|Any CPU
+ {42E1C8C0-A163-44CC-92B1-8F416F2C0B01}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = Release|Any CPU
+ {42E1C8C0-A163-44CC-92B1-8F416F2C0B01}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = Release|Any CPU
{801771CD-2C19-463A-94F8-DF546825DF47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{801771CD-2C19-463A-94F8-DF546825DF47}.Debug|Any CPU.Build.0 = Debug|Any CPU
{801771CD-2C19-463A-94F8-DF546825DF47}.MonoTouch|Any CPU.ActiveCfg = Release|Any CPU
{801771CD-2C19-463A-94F8-DF546825DF47}.Release|Any CPU.ActiveCfg = Release|Any CPU
{801771CD-2C19-463A-94F8-DF546825DF47}.Release|Any CPU.Build.0 = Release|Any CPU
+ {801771CD-2C19-463A-94F8-DF546825DF47}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = Release|Any CPU
+ {801771CD-2C19-463A-94F8-DF546825DF47}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = Release|Any CPU
{12FA52E0-E648-42B3-9F67-782011AD20C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{12FA52E0-E648-42B3-9F67-782011AD20C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{12FA52E0-E648-42B3-9F67-782011AD20C4}.MonoTouch|Any CPU.ActiveCfg = Release|Any CPU
{12FA52E0-E648-42B3-9F67-782011AD20C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{12FA52E0-E648-42B3-9F67-782011AD20C4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {12FA52E0-E648-42B3-9F67-782011AD20C4}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = Release|Any CPU
+ {12FA52E0-E648-42B3-9F67-782011AD20C4}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = Release|Any CPU
+ {5A315F92-80D2-4C60-A5A4-22E027AC7E7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5A315F92-80D2-4C60-A5A4-22E027AC7E7E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5A315F92-80D2-4C60-A5A4-22E027AC7E7E}.MonoTouch|Any CPU.ActiveCfg = MonoTouch|Any CPU
+ {5A315F92-80D2-4C60-A5A4-22E027AC7E7E}.MonoTouch|Any CPU.Build.0 = MonoTouch|Any CPU
+ {5A315F92-80D2-4C60-A5A4-22E027AC7E7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5A315F92-80D2-4C60-A5A4-22E027AC7E7E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5A315F92-80D2-4C60-A5A4-22E027AC7E7E}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = STATIC_ONLY NO_EXPRESSIONS|Any CPU
+ {5A315F92-80D2-4C60-A5A4-22E027AC7E7E}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = STATIC_ONLY NO_EXPRESSIONS|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
View
8 tests/MasterHost/MasterHost.csproj
@@ -43,10 +43,6 @@
<Reference Include="ServiceStack.OrmLite.Sqlite">
<HintPath>..\..\lib\ServiceStack.OrmLite.Sqlite.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.ServiceInterface, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\..\lib\ServiceStack.ServiceInterface.dll</HintPath>
- </Reference>
<Reference Include="ServiceStack.Text, Version=2.0.8.8681, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\ServiceStack.Text.dll</HintPath>
@@ -101,6 +97,10 @@
<Project>{42E1C8C0-A163-44CC-92B1-8F416F2C0B01}</Project>
<Name>ServiceStack.Interfaces</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\src\ServiceStack.ServiceInterface\ServiceStack.ServiceInterface.csproj">
+ <Project>{5A315F92-80D2-4C60-A5A4-22E027AC7E7E}</Project>
+ <Name>ServiceStack.ServiceInterface</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\src\ServiceStack\ServiceStack.csproj">
<Project>{680A1709-25EB-4D52-A87F-EE03FFD94BAA}</Project>
<Name>ServiceStack</Name>
View
3 tests/ServiceStack.Common.Tests/ServiceStack.Common.Tests.csproj
@@ -89,9 +89,6 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\tests\ServiceStack.OrmLite.Sqlite.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.ServiceInterface">
- <HintPath>..\..\lib\ServiceStack.ServiceInterface.dll</HintPath>
- </Reference>
<Reference Include="ServiceStack.Text, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\ServiceStack.Text.dll</HintPath>
View
7 tests/ServiceStack.Messaging.Tests/ServiceStack.Messaging.Tests.csproj
@@ -79,9 +79,6 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\tests\ServiceStack.Redis.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.ServiceInterface">
- <HintPath>..\..\lib\ServiceStack.ServiceInterface.dll</HintPath>
- </Reference>
<Reference Include="ServiceStack.Text, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\ServiceStack.Text.dll</HintPath>
@@ -126,6 +123,10 @@
<Project>{42E1C8C0-A163-44CC-92B1-8F416F2C0B01}</Project>
<Name>ServiceStack.Interfaces</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\src\ServiceStack.ServiceInterface\ServiceStack.ServiceInterface.csproj">
+ <Project>{5A315F92-80D2-4C60-A5A4-22E027AC7E7E}</Project>
+ <Name>ServiceStack.ServiceInterface</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\src\ServiceStack\ServiceStack.csproj">
<Project>{680A1709-25EB-4D52-A87F-EE03FFD94BAA}</Project>
<Name>ServiceStack</Name>
View
18 tests/ServiceStack.Messaging.Tests/Services/MessagingServiceBase.cs
@@ -1,10 +1,10 @@
-using ServiceStack.ServiceInterface;
-
-namespace ServiceStack.Messaging.Tests.Services
-{
- public abstract class MessagingServiceBase<T>
- : AsyncServiceBase<T>
- {
- }
-
+using ServiceStack.ServiceInterface;
+
+namespace ServiceStack.Messaging.Tests.Services
+{
+ public abstract class MessagingServiceBase<T>
+ : AsyncServiceBase<T>
+ {
+ }
+
}
View
7 tests/ServiceStack.ServiceHost.Tests/ServiceStack.ServiceHost.Tests.csproj
@@ -84,9 +84,6 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\tests\ServiceStack.OrmLite.Sqlite.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.ServiceInterface">
- <HintPath>..\..\lib\ServiceStack.ServiceInterface.dll</HintPath>
- </Reference>
<Reference Include="ServiceStack.Text">
<HintPath>..\..\lib\ServiceStack.Text.dll</HintPath>
</Reference>
@@ -183,6 +180,10 @@
<Project>{42E1C8C0-A163-44CC-92B1-8F416F2C0B01}</Project>
<Name>ServiceStack.Interfaces</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\src\ServiceStack.ServiceInterface\ServiceStack.ServiceInterface.csproj">
+ <Project>{5A315F92-80D2-4C60-A5A4-22E027AC7E7E}</Project>
+ <Name>ServiceStack.ServiceInterface</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\src\ServiceStack\ServiceStack.csproj">
<Project>{680A1709-25EB-4D52-A87F-EE03FFD94BAA}</Project>
<Name>ServiceStack</Name>
View
4 tests/ServiceStack.ServiceModel.Tests/ServiceStack.ServiceModel.Tests.csproj
@@ -87,10 +87,6 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\tests\ServiceStack.Redis.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.ServiceInterface, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\..\lib\ServiceStack.ServiceInterface.dll</HintPath>
- </Reference>
<Reference Include="ServiceStack.Text, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\ServiceStack.Text.dll</HintPath>
View
10 tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStack.WebHost.Endpoints.Tests.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -122,10 +122,6 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\ServiceStack.Text.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.ServiceInterface, Version=1.0.4124.855, Culture=neutral, PublicKeyToken=null">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\..\lib\ServiceStack.ServiceInterface.dll</HintPath>
- </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AppHostListenerBaseTests.cs" />
@@ -213,6 +209,10 @@
<Project>{42E1C8C0-A163-44CC-92B1-8F416F2C0B01}</Project>
<Name>ServiceStack.Interfaces</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\src\ServiceStack.ServiceInterface\ServiceStack.ServiceInterface.csproj">
+ <Project>{5A315F92-80D2-4C60-A5A4-22E027AC7E7E}</Project>
+ <Name>ServiceStack.ServiceInterface</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\src\ServiceStack\ServiceStack.csproj">
<Project>{680A1709-25EB-4D52-A87F-EE03FFD94BAA}</Project>
<Name>ServiceStack</Name>
View
7 tests/ServiceStack.WebHost.IntegrationTests/ServiceStack.WebHost.IntegrationTests.csproj
@@ -63,9 +63,6 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\tests\ServiceStack.Redis.dll</HintPath>
</Reference>
- <Reference Include="ServiceStack.ServiceInterface">
- <HintPath>..\..\lib\ServiceStack.ServiceInterface.dll</HintPath>
- </Reference>
<Reference Include="ServiceStack.Text, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\ServiceStack.Text.dll</HintPath>
@@ -173,6 +170,10 @@
<Project>{42E1C8C0-A163-44CC-92B1-8F416F2C0B01}</Project>
<Name>ServiceStack.Interfaces</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\src\ServiceStack.ServiceInterface\ServiceStack.ServiceInterface.csproj">
+ <Project>{5A315F92-80D2-4C60-A5A4-22E027AC7E7E}</Project>
+ <Name>ServiceStack.ServiceInterface</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\src\ServiceStack\ServiceStack.csproj">
<Project>{680A1709-25EB-4D52-A87F-EE03FFD94BAA}</Project>
<Name>ServiceStack</Name>

0 comments on commit 57af1ce

Please sign in to comment.