diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 99ec146d71..8ecf4ad4d6 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -29,7 +29,7 @@ using SocketHttpListener.Primitives; namespace Emby.Server.Implementations.HttpServer { - public class HttpListenerHost : ServiceStackHost, IHttpServer + public class HttpListenerHost : IHttpServer, IDisposable { private string DefaultRedirectPath { get; set; } @@ -62,7 +62,10 @@ namespace Emby.Server.Implementations.HttpServer private readonly bool _enableDualModeSockets; public List> RequestFilters { get; set; } - private Dictionary ServiceOperationsMap = new Dictionary(); + public List> ResponseFilters { get; set; } + + private readonly Dictionary ServiceOperationsMap = new Dictionary(); + public static HttpListenerHost Instance { get; protected set; } public HttpListenerHost(IServerApplicationHost applicationHost, ILogger logger, @@ -71,6 +74,8 @@ namespace Emby.Server.Implementations.HttpServer string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IJsonSerializer jsonSerializer, IXmlSerializer xmlSerializer, IEnvironmentInfo environment, ICertificate certificate, IStreamFactory streamFactory, Func> funcParseFn, bool enableDualModeSockets) : base() { + Instance = this; + _appHost = applicationHost; DefaultRedirectPath = defaultRedirectPath; _networkManager = networkManager; @@ -90,6 +95,7 @@ namespace Emby.Server.Implementations.HttpServer _logger = logger; RequestFilters = new List>(); + ResponseFilters = new List>(); } public string GlobalResponse { get; set; } @@ -112,7 +118,7 @@ namespace Emby.Server.Implementations.HttpServer } } - public override object CreateInstance(Type type) + public object CreateInstance(Type type) { return _appHost.CreateInstance(type); } @@ -168,12 +174,12 @@ namespace Emby.Server.Implementations.HttpServer private IHasRequestFilter[] GetRequestFilterAttributes(Type requestDtoType) { - var attributes = requestDtoType.AllAttributes().OfType().ToList(); + var attributes = requestDtoType.GetTypeInfo().GetCustomAttributes(true).OfType().ToList(); var serviceType = GetServiceTypeByRequest(requestDtoType); if (serviceType != null) { - attributes.AddRange(serviceType.AllAttributes().OfType()); + attributes.AddRange(serviceType.GetTypeInfo().GetCustomAttributes(true).OfType()); } attributes.Sort((x, y) => x.Priority - y.Priority); @@ -611,7 +617,7 @@ namespace Emby.Server.Implementations.HttpServer _logger.Error("Path parts empty for PathInfo: {0}, Url: {1}", pathInfo, httpReq.RawUrl); return null; } - + string contentType; var restPath = ServiceHandler.FindMatchingRestPath(httpReq.HttpMethod, pathInfo, _logger, out contentType); @@ -658,8 +664,6 @@ namespace Emby.Server.Implementations.HttpServer _logger.Info("Calling ServiceStack AppHost.Init"); - Instance = this; - ServiceController.Init(this); var requestFilters = _appHost.GetExports().ToList(); @@ -668,12 +672,12 @@ namespace Emby.Server.Implementations.HttpServer RequestFilters.Add(filter.Filter); } - GlobalResponseFilters.Add(new ResponseFilter(_logger).FilterResponse); + ResponseFilters.Add(new ResponseFilter(_logger).FilterResponse); } - public override RouteAttribute[] GetRouteAttributes(Type requestType) + public RouteAttribute[] GetRouteAttributes(Type requestType) { - var routes = requestType.AllAttributes(); + var routes = requestType.GetTypeInfo().GetCustomAttributes(true).ToList(); var clone = routes.ToList(); foreach (var route in clone) @@ -703,27 +707,27 @@ namespace Emby.Server.Implementations.HttpServer return routes.ToArray(); } - public override Func GetParseFn(Type propertyType) + public Func GetParseFn(Type propertyType) { return _funcParseFn(propertyType); } - public override void SerializeToJson(object o, Stream stream) + public void SerializeToJson(object o, Stream stream) { _jsonSerializer.SerializeToStream(o, stream); } - public override void SerializeToXml(object o, Stream stream) + public void SerializeToXml(object o, Stream stream) { _xmlSerializer.SerializeToStream(o, stream); } - public override object DeserializeXml(Type type, Stream stream) + public object DeserializeXml(Type type, Stream stream) { return _xmlSerializer.DeserializeFromStream(type, stream); } - public override object DeserializeJson(Type type, Stream stream) + public object DeserializeJson(Type type, Stream stream) { return _jsonSerializer.DeserializeFromStream(stream, type); } @@ -764,7 +768,7 @@ namespace Emby.Server.Implementations.HttpServer { if (_disposed) return; - base.Dispose(); + Dispose(); lock (_disposeLock) { @@ -779,7 +783,7 @@ namespace Emby.Server.Implementations.HttpServer } } - public override void Dispose() + public void Dispose() { Dispose(true); GC.SuppressFinalize(this); diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index 3f756fc7ad..20b345fa1e 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -204,7 +204,7 @@ namespace Emby.Server.Implementations.HttpServer using (var ms = new MemoryStream()) { var contentType = request.ResponseContentType; - var writerFn = RequestHelper.GetResponseWriter(contentType); + var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType); writerFn(dto, ms); diff --git a/Emby.Server.Implementations/Services/RequestHelper.cs b/Emby.Server.Implementations/Services/RequestHelper.cs index 8cfc3d0897..7538d3102f 100644 --- a/Emby.Server.Implementations/Services/RequestHelper.cs +++ b/Emby.Server.Implementations/Services/RequestHelper.cs @@ -1,40 +1,40 @@ using System; using System.IO; -using ServiceStack; +using Emby.Server.Implementations.HttpServer; namespace Emby.Server.Implementations.Services { public class RequestHelper { - public static Func GetRequestReader(string contentType) + public static Func GetRequestReader(HttpListenerHost host, string contentType) { switch (GetContentTypeWithoutEncoding(contentType)) { case "application/xml": case "text/xml": case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml - return ServiceStackHost.Instance.DeserializeXml; + return host.DeserializeXml; case "application/json": case "text/json": - return ServiceStackHost.Instance.DeserializeJson; + return host.DeserializeJson; } return null; } - public static Action GetResponseWriter(string contentType) + public static Action GetResponseWriter(HttpListenerHost host, string contentType) { switch (GetContentTypeWithoutEncoding(contentType)) { case "application/xml": case "text/xml": case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml - return (o, s) => ServiceStackHost.Instance.SerializeToXml(o, s); + return host.SerializeToXml; case "application/json": case "text/json": - return (o, s) => ServiceStackHost.Instance.SerializeToJson(o, s); + return host.SerializeToJson; } return null; diff --git a/Emby.Server.Implementations/Services/ResponseHelper.cs b/Emby.Server.Implementations/Services/ResponseHelper.cs index 1af70ad7f6..d4ce1cabfe 100644 --- a/Emby.Server.Implementations/Services/ResponseHelper.cs +++ b/Emby.Server.Implementations/Services/ResponseHelper.cs @@ -5,6 +5,7 @@ using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; +using Emby.Server.Implementations.HttpServer; using MediaBrowser.Model.Services; namespace Emby.Server.Implementations.Services @@ -161,7 +162,7 @@ namespace Emby.Server.Implementations.Services public static async Task WriteObject(IRequest request, object result, IResponse response) { var contentType = request.ResponseContentType; - var serializer = RequestHelper.GetResponseWriter(contentType); + var serializer = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType); using (var ms = new MemoryStream()) { diff --git a/Emby.Server.Implementations/Services/ServiceController.cs b/Emby.Server.Implementations/Services/ServiceController.cs index 714a16df58..da8af89c8b 100644 --- a/Emby.Server.Implementations/Services/ServiceController.cs +++ b/Emby.Server.Implementations/Services/ServiceController.cs @@ -53,28 +53,58 @@ namespace Emby.Server.Implementations.Services ServiceExecGeneral.CreateServiceRunnersFor(requestType, actions); - var returnMarker = requestType.GetTypeWithGenericTypeDefinitionOf(typeof(IReturn<>)); + var returnMarker = GetTypeWithGenericTypeDefinitionOf(requestType, typeof(IReturn<>)); var responseType = returnMarker != null ? GetGenericArguments(returnMarker)[0] : mi.ReturnType != typeof(object) && mi.ReturnType != typeof(void) ? mi.ReturnType : Type.GetType(requestType.FullName + "Response"); - RegisterRestPaths(requestType); + RegisterRestPaths(appHost, requestType); appHost.AddServiceInfo(serviceType, requestType, responseType); } } + private static Type GetTypeWithGenericTypeDefinitionOf(Type type, Type genericTypeDefinition) + { + foreach (var t in type.GetTypeInfo().ImplementedInterfaces) + { + if (t.GetTypeInfo().IsGenericType && t.GetGenericTypeDefinition() == genericTypeDefinition) + { + return t; + } + } + + var genericType = FirstGenericType(type); + if (genericType != null && genericType.GetGenericTypeDefinition() == genericTypeDefinition) + { + return genericType; + } + + return null; + } + + public static Type FirstGenericType(Type type) + { + while (type != null) + { + if (type.GetTypeInfo().IsGenericType) + return type; + + type = type.GetTypeInfo().BaseType; + } + return null; + } + public readonly Dictionary> RestPathMap = new Dictionary>(StringComparer.OrdinalIgnoreCase); - public void RegisterRestPaths(Type requestType) + public void RegisterRestPaths(HttpListenerHost appHost, Type requestType) { - var appHost = ServiceStackHost.Instance; var attrs = appHost.GetRouteAttributes(requestType); - foreach (MediaBrowser.Model.Services.RouteAttribute attr in attrs) + foreach (RouteAttribute attr in attrs) { - var restPath = new RestPath(requestType, attr.Path, attr.Verbs, attr.Summary, attr.Notes); + var restPath = new RestPath(appHost.CreateInstance, appHost.GetParseFn, requestType, attr.Path, attr.Verbs, attr.Summary, attr.Notes); if (!restPath.IsValid) throw new NotSupportedException(string.Format( diff --git a/Emby.Server.Implementations/Services/ServiceHandler.cs b/Emby.Server.Implementations/Services/ServiceHandler.cs index 003776f9c9..93126426c6 100644 --- a/Emby.Server.Implementations/Services/ServiceHandler.cs +++ b/Emby.Server.Implementations/Services/ServiceHandler.cs @@ -59,17 +59,17 @@ namespace Emby.Server.Implementations.Services } } - protected static object CreateContentTypeRequest(IRequest httpReq, Type requestType, string contentType) + protected static object CreateContentTypeRequest(HttpListenerHost host, IRequest httpReq, Type requestType, string contentType) { if (!string.IsNullOrEmpty(contentType) && httpReq.ContentLength > 0) { - var deserializer = RequestHelper.GetRequestReader(contentType); + var deserializer = RequestHelper.GetRequestReader(host, contentType); if (deserializer != null) { return deserializer(requestType, httpReq.InputStream); } } - return ServiceStackHost.Instance.CreateInstance(requestType); //Return an empty DTO, even for empty request bodies + return host.CreateInstance(requestType); } public static RestPath FindMatchingRestPath(string httpMethod, string pathInfo, ILogger logger, out string contentType) @@ -137,7 +137,7 @@ namespace Emby.Server.Implementations.Services if (ResponseContentType != null) httpReq.ResponseContentType = ResponseContentType; - var request = httpReq.Dto = CreateRequest(httpReq, restPath, logger); + var request = httpReq.Dto = CreateRequest(appHost, httpReq, restPath, logger); appHost.ApplyRequestFilters(httpReq, httpRes, request); @@ -146,7 +146,7 @@ namespace Emby.Server.Implementations.Services var response = await HandleResponseAsync(rawResponse).ConfigureAwait(false); // Apply response filters - foreach (var responseFilter in appHost.GlobalResponseFilters) + foreach (var responseFilter in appHost.ResponseFilters) { responseFilter(httpReq, httpRes, response); } @@ -154,18 +154,18 @@ namespace Emby.Server.Implementations.Services await ResponseHelper.WriteToResponse(httpRes, httpReq, response).ConfigureAwait(false); } - public static object CreateRequest(IRequest httpReq, RestPath restPath, ILogger logger) + public static object CreateRequest(HttpListenerHost host, IRequest httpReq, RestPath restPath, ILogger logger) { var requestType = restPath.RequestType; if (RequireqRequestStream(requestType)) { // Used by IRequiresRequestStream - return CreateRequiresRequestStreamRequest(httpReq, requestType); + return CreateRequiresRequestStreamRequest(host, httpReq, requestType); } var requestParams = GetFlattenedRequestParams(httpReq); - return CreateRequest(httpReq, restPath, requestParams); + return CreateRequest(host, httpReq, restPath, requestParams); } private static bool RequireqRequestStream(Type requestType) @@ -175,19 +175,19 @@ namespace Emby.Server.Implementations.Services return requiresRequestStreamTypeInfo.IsAssignableFrom(requestType.GetTypeInfo()); } - private static IRequiresRequestStream CreateRequiresRequestStreamRequest(IRequest req, Type requestType) + private static IRequiresRequestStream CreateRequiresRequestStreamRequest(HttpListenerHost host, IRequest req, Type requestType) { var restPath = GetRoute(req); - var request = ServiceHandler.CreateRequest(req, restPath, GetRequestParams(req), ServiceStackHost.Instance.CreateInstance(requestType)); + var request = ServiceHandler.CreateRequest(req, restPath, GetRequestParams(req), host.CreateInstance(requestType)); var rawReq = (IRequiresRequestStream)request; rawReq.RequestStream = req.InputStream; return rawReq; } - public static object CreateRequest(IRequest httpReq, RestPath restPath, Dictionary requestParams) + public static object CreateRequest(HttpListenerHost host, IRequest httpReq, RestPath restPath, Dictionary requestParams) { - var requestDto = CreateContentTypeRequest(httpReq, restPath.RequestType, httpReq.ContentType); + var requestDto = CreateContentTypeRequest(host, httpReq, restPath.RequestType, httpReq.ContentType); return CreateRequest(httpReq, restPath, requestParams, requestDto); } diff --git a/ServiceStack/ReflectionExtensions.cs b/ServiceStack/ReflectionExtensions.cs deleted file mode 100644 index 4bbf9e6ac5..0000000000 --- a/ServiceStack/ReflectionExtensions.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; - -namespace ServiceStack -{ - public static class ReflectionExtensions - { - public static Type FirstGenericType(this Type type) - { - while (type != null) - { - if (type.IsGeneric()) - return type; - - type = type.BaseType(); - } - return null; - } - - public static Type GetTypeWithGenericTypeDefinitionOf(this Type type, Type genericTypeDefinition) - { - foreach (var t in type.GetTypeInterfaces()) - { - if (t.IsGeneric() && t.GetGenericTypeDefinition() == genericTypeDefinition) - { - return t; - } - } - - var genericType = type.FirstGenericType(); - if (genericType != null && genericType.GetGenericTypeDefinition() == genericTypeDefinition) - { - return genericType; - } - - return null; - } - - public static PropertyInfo[] GetPublicProperties(this Type type) - { - if (type.IsInterface()) - { - var propertyInfos = new List(); - - var considered = new List(); - var queue = new Queue(); - considered.Add(type); - queue.Enqueue(type); - - while (queue.Count > 0) - { - var subType = queue.Dequeue(); - foreach (var subInterface in subType.GetTypeInterfaces()) - { - if (considered.Contains(subInterface)) continue; - - considered.Add(subInterface); - queue.Enqueue(subInterface); - } - - var typeProperties = subType.GetTypesPublicProperties(); - - var newPropertyInfos = typeProperties - .Where(x => !propertyInfos.Contains(x)); - - propertyInfos.InsertRange(0, newPropertyInfos); - } - - return propertyInfos.ToArray(); - } - - return type.GetTypesPublicProperties() - .Where(t => t.GetIndexParameters().Length == 0) // ignore indexed properties - .ToArray(); - } - - public const string DataMember = "DataMemberAttribute"; - - internal static string[] IgnoreAttributesNamed = new[] { - "IgnoreDataMemberAttribute", - "JsonIgnoreAttribute" - }; - - public static PropertyInfo[] GetSerializableProperties(this Type type) - { - var properties = type.GetPublicProperties(); - return properties.OnlySerializableProperties(type); - } - - - private static List _excludeTypes = new List { typeof(Stream) }; - - public static PropertyInfo[] OnlySerializableProperties(this PropertyInfo[] properties, Type type = null) - { - var readableProperties = properties.Where(x => x.PropertyGetMethod(nonPublic: false) != null); - - // else return those properties that are not decorated with IgnoreDataMember - return readableProperties - .Where(prop => prop.AllAttributes() - .All(attr => - { - var name = attr.GetType().Name; - return !IgnoreAttributesNamed.Contains(name); - })) - .Where(prop => !_excludeTypes.Contains(prop.PropertyType)) - .ToArray(); - } - } - - public static class PlatformExtensions //Because WinRT is a POS - { - public static bool IsInterface(this Type type) - { - return type.GetTypeInfo().IsInterface; - } - - public static bool IsGeneric(this Type type) - { - return type.GetTypeInfo().IsGenericType; - } - - public static Type BaseType(this Type type) - { - return type.GetTypeInfo().BaseType; - } - - public static Type[] GetTypeInterfaces(this Type type) - { - return type.GetTypeInfo().ImplementedInterfaces.ToArray(); - } - - internal static PropertyInfo[] GetTypesPublicProperties(this Type subType) - { - var pis = new List(); - foreach (var pi in subType.GetRuntimeProperties()) - { - var mi = pi.GetMethod ?? pi.SetMethod; - if (mi != null && mi.IsStatic) continue; - pis.Add(pi); - } - return pis.ToArray(); - } - - public static MethodInfo PropertyGetMethod(this PropertyInfo pi, bool nonPublic = false) - { - return pi.GetMethod; - } - - public static object[] AllAttributes(this PropertyInfo propertyInfo) - { - return propertyInfo.GetCustomAttributes(true).ToArray(); - } - - public static object[] AllAttributes(this Type type) - { - return type.GetTypeInfo().GetCustomAttributes(true).ToArray(); - } - - public static List AllAttributes(this Type type) - where TAttr : Attribute - { - return type.GetTypeInfo().GetCustomAttributes(true).ToList(); - } - } -} diff --git a/ServiceStack/RestPath.cs b/ServiceStack/RestPath.cs index 5e86001d36..afd1f73e1a 100644 --- a/ServiceStack/RestPath.cs +++ b/ServiceStack/RestPath.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Reflection; using System.Text; using MediaBrowser.Model.Logging; using ServiceStack.Serialization; @@ -71,7 +73,7 @@ namespace ServiceStack public static string[] GetPathPartsForMatching(string pathInfo) { var parts = pathInfo.ToLower().Split(PathSeperatorChar) - .Where(x => !string.IsNullOrEmpty(x)).ToArray(); + .Where(x => !String.IsNullOrEmpty(x)).ToArray(); return parts; } @@ -107,14 +109,14 @@ namespace ServiceStack return list; } - public RestPath(Type requestType, string path, string verbs, string summary = null, string notes = null) + public RestPath(Func createInstanceFn, Func> getParseFn, Type requestType, string path, string verbs, string summary = null, string notes = null) { this.RequestType = requestType; this.Summary = summary; this.Notes = notes; this.restPath = path; - this.allowsAllVerbs = verbs == null || string.Equals(verbs, WildCard, StringComparison.OrdinalIgnoreCase); + this.allowsAllVerbs = verbs == null || String.Equals(verbs, WildCard, StringComparison.OrdinalIgnoreCase); if (!this.allowsAllVerbs) { this.allowedVerbs = verbs.ToUpper(); @@ -126,7 +128,7 @@ namespace ServiceStack var hasSeparators = new List(); foreach (var component in this.restPath.Split(PathSeperatorChar)) { - if (string.IsNullOrEmpty(component)) continue; + if (String.IsNullOrEmpty(component)) continue; if (StringContains(component, VariablePrefix) && component.IndexOf(ComponentSeperator) != -1) @@ -199,19 +201,95 @@ namespace ServiceStack this.IsValid = sbHashKey.Length > 0; this.UniqueMatchHashKey = sbHashKey.ToString(); - this.typeDeserializer = new StringMapTypeDeserializer(this.RequestType); + this.typeDeserializer = new StringMapTypeDeserializer(createInstanceFn, getParseFn, this.RequestType); RegisterCaseInsenstivePropertyNameMappings(); } private void RegisterCaseInsenstivePropertyNameMappings() { - foreach (var propertyInfo in RequestType.GetSerializableProperties()) + foreach (var propertyInfo in GetSerializableProperties(RequestType)) { var propertyName = propertyInfo.Name; propertyNamesMap.Add(propertyName.ToLower(), propertyName); } } + internal static string[] IgnoreAttributesNamed = new[] { + "IgnoreDataMemberAttribute", + "JsonIgnoreAttribute" + }; + + + private static List _excludeTypes = new List { typeof(Stream) }; + + internal static PropertyInfo[] GetSerializableProperties(Type type) + { + var properties = GetPublicProperties(type); + var readableProperties = properties.Where(x => x.GetMethod != null); + + // else return those properties that are not decorated with IgnoreDataMember + return readableProperties + .Where(prop => prop.GetCustomAttributes(true) + .All(attr => + { + var name = attr.GetType().Name; + return !IgnoreAttributesNamed.Contains(name); + })) + .Where(prop => !_excludeTypes.Contains(prop.PropertyType)) + .ToArray(); + } + + private static PropertyInfo[] GetPublicProperties(Type type) + { + if (type.GetTypeInfo().IsInterface) + { + var propertyInfos = new List(); + + var considered = new List(); + var queue = new Queue(); + considered.Add(type); + queue.Enqueue(type); + + while (queue.Count > 0) + { + var subType = queue.Dequeue(); + foreach (var subInterface in subType.GetTypeInfo().ImplementedInterfaces) + { + if (considered.Contains(subInterface)) continue; + + considered.Add(subInterface); + queue.Enqueue(subInterface); + } + + var typeProperties = GetTypesPublicProperties(subType); + + var newPropertyInfos = typeProperties + .Where(x => !propertyInfos.Contains(x)); + + propertyInfos.InsertRange(0, newPropertyInfos); + } + + return propertyInfos.ToArray(); + } + + return GetTypesPublicProperties(type) + .Where(t => t.GetIndexParameters().Length == 0) // ignore indexed properties + .ToArray(); + } + + private static PropertyInfo[] GetTypesPublicProperties(Type subType) + { + var pis = new List(); + foreach (var pi in subType.GetRuntimeProperties()) + { + var mi = pi.GetMethod ?? pi.SetMethod; + if (mi != null && mi.IsStatic) continue; + pis.Add(pi); + } + return pis.ToArray(); + } + + public bool IsValid { get; set; } /// @@ -243,7 +321,7 @@ namespace ServiceStack score += Math.Max((10 - VariableArgsCount), 1) * 100; //Exact verb match is better than ANY - var exactVerb = string.Equals(httpMethod, AllowedVerbs, StringComparison.OrdinalIgnoreCase); + var exactVerb = String.Equals(httpMethod, AllowedVerbs, StringComparison.OrdinalIgnoreCase); score += exactVerb ? 10 : 1; return score; @@ -339,7 +417,7 @@ namespace ServiceStack private bool LiteralsEqual(string str1, string str2) { // Most cases - if (string.Equals(str1, str2, StringComparison.OrdinalIgnoreCase)) + if (String.Equals(str1, str2, StringComparison.OrdinalIgnoreCase)) { return true; } @@ -349,7 +427,7 @@ namespace ServiceStack str2 = str2.ToUpperInvariant(); // Invariant IgnoreCase would probably be better but it's not available in PCL - return string.Equals(str1, str2, StringComparison.CurrentCultureIgnoreCase); + return String.Equals(str1, str2, StringComparison.CurrentCultureIgnoreCase); } private bool ExplodeComponents(ref string[] withPathInfoParts) @@ -358,7 +436,7 @@ namespace ServiceStack for (var i = 0; i < withPathInfoParts.Length; i++) { var component = withPathInfoParts[i]; - if (string.IsNullOrEmpty(component)) continue; + if (String.IsNullOrEmpty(component)) continue; if (this.PathComponentsCount != this.TotalComponentsCount && this.componentsWithSeparators[i]) @@ -380,7 +458,7 @@ namespace ServiceStack public object CreateRequest(string pathInfo, Dictionary queryStringAndFormData, object fromInstance) { var requestComponents = pathInfo.Split(PathSeperatorChar) - .Where(x => !string.IsNullOrEmpty(x)).ToArray(); + .Where(x => !String.IsNullOrEmpty(x)).ToArray(); ExplodeComponents(ref requestComponents); @@ -390,7 +468,7 @@ namespace ServiceStack && requestComponents.Length >= this.TotalComponentsCount - this.wildcardCount; if (!isValidWildCardPath) - throw new ArgumentException(string.Format( + throw new ArgumentException(String.Format( "Path Mismatch: Request Path '{0}' has invalid number of components compared to: '{1}'", pathInfo, this.restPath)); } @@ -409,7 +487,7 @@ namespace ServiceStack string propertyNameOnRequest; if (!this.propertyNamesMap.TryGetValue(variableName.ToLower(), out propertyNameOnRequest)) { - if (string.Equals("ignore", variableName, StringComparison.OrdinalIgnoreCase)) + if (String.Equals("ignore", variableName, StringComparison.OrdinalIgnoreCase)) { pathIx++; continue; @@ -439,12 +517,12 @@ namespace ServiceStack // hits a match for the next element in the definition (which must be a literal) // It may consume 0 or more path parts var stopLiteral = i == this.TotalComponentsCount - 1 ? null : this.literalsToMatch[i + 1]; - if (!string.Equals(requestComponents[pathIx], stopLiteral, StringComparison.OrdinalIgnoreCase)) + if (!String.Equals(requestComponents[pathIx], stopLiteral, StringComparison.OrdinalIgnoreCase)) { var sb = new StringBuilder(); sb.Append(value); pathIx++; - while (!string.Equals(requestComponents[pathIx], stopLiteral, StringComparison.OrdinalIgnoreCase)) + while (!String.Equals(requestComponents[pathIx], stopLiteral, StringComparison.OrdinalIgnoreCase)) { sb.Append(PathSeperatorChar + requestComponents[pathIx++]); } diff --git a/ServiceStack/ServiceStack.csproj b/ServiceStack/ServiceStack.csproj index 36c467b8e2..33226971e9 100644 --- a/ServiceStack/ServiceStack.csproj +++ b/ServiceStack/ServiceStack.csproj @@ -69,9 +69,7 @@ false - - diff --git a/ServiceStack/ServiceStackHost.cs b/ServiceStack/ServiceStackHost.cs deleted file mode 100644 index 09fe9a2421..0000000000 --- a/ServiceStack/ServiceStackHost.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Service Stack LLC. All Rights Reserved. -// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt - - -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; -using MediaBrowser.Model.Services; - -namespace ServiceStack -{ - public abstract class ServiceStackHost : IDisposable - { - public static ServiceStackHost Instance { get; protected set; } - - protected ServiceStackHost() - { - GlobalResponseFilters = new List>(); - } - - public abstract object CreateInstance(Type type); - - public List> GlobalResponseFilters { get; set; } - - public abstract RouteAttribute[] GetRouteAttributes(Type requestType); - - public abstract Func GetParseFn(Type propertyType); - - public abstract void SerializeToJson(object o, Stream stream); - public abstract void SerializeToXml(object o, Stream stream); - public abstract object DeserializeXml(Type type, Stream stream); - public abstract object DeserializeJson(Type type, Stream stream); - - public virtual void Dispose() - { - //JsConfig.Reset(); //Clears Runtime Attributes - - Instance = null; - } - } -} diff --git a/ServiceStack/StringMapTypeDeserializer.cs b/ServiceStack/StringMapTypeDeserializer.cs index 8b76c39d04..82724fc4a8 100644 --- a/ServiceStack/StringMapTypeDeserializer.cs +++ b/ServiceStack/StringMapTypeDeserializer.cs @@ -34,14 +34,19 @@ namespace ServiceStack.Serialization if (propertyType == typeof(string)) return s => s; - return ServiceStackHost.Instance.GetParseFn(propertyType); + return _GetParseFn(propertyType); } - public StringMapTypeDeserializer(Type type) + private readonly Func _CreateInstanceFn; + private readonly Func> _GetParseFn; + + public StringMapTypeDeserializer(Func createInstanceFn, Func> getParseFn, Type type) { + _CreateInstanceFn = createInstanceFn; + _GetParseFn = getParseFn; this.type = type; - foreach (var propertyInfo in type.GetSerializableProperties()) + foreach (var propertyInfo in RestPath.GetSerializableProperties(type)) { var propertySetFn = TypeAccessor.GetSetPropertyMethod(type, propertyInfo); var propertyType = propertyInfo.PropertyType; @@ -59,7 +64,7 @@ namespace ServiceStack.Serialization PropertySerializerEntry propertySerializerEntry = null; if (instance == null) - instance = ServiceStackHost.Instance.CreateInstance(type); + instance = _CreateInstanceFn(type); foreach (var pair in keyValuePairs.Where(x => !string.IsNullOrEmpty(x.Value))) {