localization fixes

This commit is contained in:
Luke Pulverenti
2017-02-12 20:07:48 -05:00
parent a6e7438987
commit 0a03d7ad9f
22 changed files with 513 additions and 882 deletions

View File

@@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using ServiceStack;
namespace ServiceStack.Support.WebHost
{
public static class FilterAttributeCache
{
public static MediaBrowser.Model.Services.IHasRequestFilter[] GetRequestFilterAttributes(Type requestDtoType)
{
var attributes = requestDtoType.AllAttributes().OfType<MediaBrowser.Model.Services.IHasRequestFilter>().ToList();
var serviceType = ServiceStackHost.Instance.Metadata.GetServiceTypeByRequest(requestDtoType);
if (serviceType != null)
{
attributes.AddRange(serviceType.AllAttributes().OfType<MediaBrowser.Model.Services.IHasRequestFilter>());
}
attributes.Sort((x,y) => x.Priority - y.Priority);
return attributes.ToArray();
}
}
}

View File

@@ -1,27 +0,0 @@
using System;
namespace ServiceStack.Host
{
/// <summary>
/// Context to capture IService action
/// </summary>
public class ActionContext
{
public const string AnyAction = "ANY";
public string Id { get; set; }
public ActionInvokerFn ServiceAction { get; set; }
public MediaBrowser.Model.Services.IHasRequestFilter[] RequestFilters { get; set; }
public static string Key(Type serviceType, string method, string requestDtoName)
{
return serviceType.FullName + " " + method.ToUpper() + " " + requestDtoName;
}
public static string AnyKey(Type serviceType, string requestDtoName)
{
return Key(serviceType, AnyAction, requestDtoName);
}
}
}

View File

@@ -1,63 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using MediaBrowser.Model.Services;
namespace ServiceStack.Host
{
public class ContentTypes
{
public static ContentTypes Instance = new ContentTypes();
public void SerializeToStream(IRequest req, object response, Stream responseStream)
{
var contentType = req.ResponseContentType;
var serializer = GetStreamSerializer(contentType);
serializer(response, responseStream);
}
public static Action<object, Stream> GetStreamSerializer(string contentType)
{
switch (GetRealContentType(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);
case "application/json":
case "text/json":
return (o, s) => ServiceStackHost.Instance.SerializeToJson(o, s);
}
return null;
}
public Func<Type, Stream, object> GetStreamDeserializer(string contentType)
{
switch (GetRealContentType(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;
case "application/json":
case "text/json":
return ServiceStackHost.Instance.DeserializeJson;
}
return null;
}
private static string GetRealContentType(string contentType)
{
return contentType == null
? null
: contentType.Split(';')[0].ToLower().Trim();
}
}
}

View File

@@ -1,177 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Threading.Tasks;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Services;
namespace ServiceStack.Host
{
public class RestHandler
{
public string RequestName { get; set; }
public async Task<object> HandleResponseAsync(object response)
{
var taskResponse = response as Task;
if (taskResponse == null)
{
return response;
}
await taskResponse.ConfigureAwait(false);
var taskResult = ServiceStackHost.Instance.GetTaskResult(taskResponse, RequestName);
var subTask = taskResult as Task;
if (subTask != null)
{
taskResult = ServiceStackHost.Instance.GetTaskResult(subTask, RequestName);
}
return taskResult;
}
protected static object CreateContentTypeRequest(IRequest httpReq, Type requestType, string contentType)
{
if (!string.IsNullOrEmpty(contentType) && httpReq.ContentLength > 0)
{
var deserializer = ContentTypes.Instance.GetStreamDeserializer(contentType);
if (deserializer != null)
{
return deserializer(requestType, httpReq.InputStream);
}
}
return ServiceStackHost.Instance.CreateInstance(requestType); //Return an empty DTO, even for empty request bodies
}
protected static object GetCustomRequestFromBinder(IRequest httpReq, Type requestType)
{
Func<IRequest, object> requestFactoryFn;
ServiceStackHost.Instance.ServiceController.RequestTypeFactoryMap.TryGetValue(
requestType, out requestFactoryFn);
return requestFactoryFn != null ? requestFactoryFn(httpReq) : null;
}
public static RestPath FindMatchingRestPath(string httpMethod, string pathInfo, ILogger logger, out string contentType)
{
pathInfo = GetSanitizedPathInfo(pathInfo, out contentType);
return ServiceStackHost.Instance.ServiceController.GetRestPathForRequest(httpMethod, pathInfo, logger);
}
public static string GetSanitizedPathInfo(string pathInfo, out string contentType)
{
contentType = null;
var pos = pathInfo.LastIndexOf('.');
if (pos >= 0)
{
var format = pathInfo.Substring(pos + 1);
contentType = GetFormatContentType(format);
if (contentType != null)
{
pathInfo = pathInfo.Substring(0, pos);
}
}
return pathInfo;
}
private static string GetFormatContentType(string format)
{
//built-in formats
if (format == "json")
return "application/json";
if (format == "xml")
return "application/xml";
return null;
}
public RestPath GetRestPath(string httpMethod, string pathInfo)
{
if (this.RestPath == null)
{
string contentType;
this.RestPath = FindMatchingRestPath(httpMethod, pathInfo, new NullLogger(), out contentType);
if (contentType != null)
ResponseContentType = contentType;
}
return this.RestPath;
}
public RestPath RestPath { get; set; }
// Set from SSHHF.GetHandlerForPathInfo()
public string ResponseContentType { get; set; }
public async Task ProcessRequestAsync(IRequest httpReq, IResponse httpRes, string operationName)
{
var appHost = ServiceStackHost.Instance;
var restPath = GetRestPath(httpReq.Verb, httpReq.PathInfo);
if (restPath == null)
{
throw new NotSupportedException("No RestPath found for: " + httpReq.Verb + " " + httpReq.PathInfo);
}
httpReq.SetRoute(restPath);
if (ResponseContentType != null)
httpReq.ResponseContentType = ResponseContentType;
var request = httpReq.Dto = CreateRequest(httpReq, restPath);
appHost.ApplyRequestFilters(httpReq, httpRes, request);
var rawResponse = await ServiceStackHost.Instance.ServiceController.Execute(request, httpReq).ConfigureAwait(false);
var response = await HandleResponseAsync(rawResponse).ConfigureAwait(false);
appHost.ApplyResponseFilters(httpReq, httpRes, response);
await httpRes.WriteToResponse(httpReq, response).ConfigureAwait(false);
}
public static object CreateRequest(IRequest httpReq, RestPath restPath)
{
var dtoFromBinder = GetCustomRequestFromBinder(httpReq, restPath.RequestType);
if (dtoFromBinder != null)
return dtoFromBinder;
var requestParams = httpReq.GetFlattenedRequestParams();
return CreateRequest(httpReq, restPath, requestParams);
}
public static object CreateRequest(IRequest httpReq, RestPath restPath, Dictionary<string, string> requestParams)
{
var requestDto = CreateContentTypeRequest(httpReq, restPath.RequestType, httpReq.ContentType);
return CreateRequest(httpReq, restPath, requestParams, requestDto);
}
public static object CreateRequest(IRequest httpReq, RestPath restPath, Dictionary<string, string> requestParams, object requestDto)
{
string contentType;
var pathInfo = !restPath.IsWildCardPath
? GetSanitizedPathInfo(httpReq.PathInfo, out contentType)
: httpReq.PathInfo;
return restPath.CreateRequest(pathInfo, requestParams, requestDto);
}
/// <summary>
/// Used in Unit tests
/// </summary>
/// <returns></returns>
public object CreateRequest(IRequest httpReq, string operationName)
{
if (this.RestPath == null)
throw new ArgumentNullException("No RestPath found");
return CreateRequest(httpReq, this.RestPath);
}
}
}

View File

@@ -1,222 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Services;
namespace ServiceStack.Host
{
public delegate Task<object> InstanceExecFn(IRequest requestContext, object intance, object request);
public delegate object ActionInvokerFn(object intance, object request);
public delegate void VoidActionInvokerFn(object intance, object request);
public class ServiceController
{
private readonly Func<IEnumerable<Type>> _resolveServicesFn;
public ServiceController(Func<IEnumerable<Type>> resolveServicesFn)
{
_resolveServicesFn = resolveServicesFn;
this.RequestTypeFactoryMap = new Dictionary<Type, Func<IRequest, object>>();
}
public Dictionary<Type, Func<IRequest, object>> RequestTypeFactoryMap { get; set; }
public void Init()
{
foreach (var serviceType in _resolveServicesFn())
{
RegisterService(serviceType);
}
}
private Type[] GetGenericArguments(Type type)
{
return type.GetTypeInfo().IsGenericTypeDefinition
? type.GetTypeInfo().GenericTypeParameters
: type.GetTypeInfo().GenericTypeArguments;
}
public void RegisterService(Type serviceType)
{
var processedReqs = new HashSet<Type>();
var actions = ServiceExecGeneral.Reset(serviceType);
var requiresRequestStreamTypeInfo = typeof(IRequiresRequestStream).GetTypeInfo();
var appHost = ServiceStackHost.Instance;
foreach (var mi in serviceType.GetActions())
{
var requestType = mi.GetParameters()[0].ParameterType;
if (processedReqs.Contains(requestType)) continue;
processedReqs.Add(requestType);
ServiceExecGeneral.CreateServiceRunnersFor(requestType, actions);
var returnMarker = requestType.GetTypeWithGenericTypeDefinitionOf(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);
appHost.Metadata.Add(serviceType, requestType, responseType);
if (requiresRequestStreamTypeInfo.IsAssignableFrom(requestType.GetTypeInfo()))
{
this.RequestTypeFactoryMap[requestType] = req =>
{
var restPath = req.GetRoute();
var request = RestHandler.CreateRequest(req, restPath, req.GetRequestParams(), ServiceStackHost.Instance.CreateInstance(requestType));
var rawReq = (IRequiresRequestStream)request;
rawReq.RequestStream = req.InputStream;
return rawReq;
};
}
}
}
public readonly Dictionary<string, List<RestPath>> RestPathMap = new Dictionary<string, List<RestPath>>(StringComparer.OrdinalIgnoreCase);
public void RegisterRestPaths(Type requestType)
{
var appHost = ServiceStackHost.Instance;
var attrs = appHost.GetRouteAttributes(requestType);
foreach (MediaBrowser.Model.Services.RouteAttribute attr in attrs)
{
var restPath = new RestPath(requestType, attr.Path, attr.Verbs, attr.Summary, attr.Notes);
if (!restPath.IsValid)
throw new NotSupportedException(string.Format(
"RestPath '{0}' on Type '{1}' is not Valid", attr.Path, requestType.GetOperationName()));
RegisterRestPath(restPath);
}
}
private static readonly char[] InvalidRouteChars = new[] { '?', '&' };
public void RegisterRestPath(RestPath restPath)
{
if (!restPath.Path.StartsWith("/"))
throw new ArgumentException(string.Format("Route '{0}' on '{1}' must start with a '/'", restPath.Path, restPath.RequestType.GetOperationName()));
if (restPath.Path.IndexOfAny(InvalidRouteChars) != -1)
throw new ArgumentException(string.Format("Route '{0}' on '{1}' contains invalid chars. " +
"See https://github.com/ServiceStack/ServiceStack/wiki/Routing for info on valid routes.", restPath.Path, restPath.RequestType.GetOperationName()));
List<RestPath> pathsAtFirstMatch;
if (!RestPathMap.TryGetValue(restPath.FirstMatchHashKey, out pathsAtFirstMatch))
{
pathsAtFirstMatch = new List<RestPath>();
RestPathMap[restPath.FirstMatchHashKey] = pathsAtFirstMatch;
}
pathsAtFirstMatch.Add(restPath);
}
public void AfterInit()
{
var appHost = ServiceStackHost.Instance;
//Register any routes configured on Metadata.Routes
foreach (var restPath in appHost.RestPaths)
{
RegisterRestPath(restPath);
}
//Sync the RestPaths collections
appHost.RestPaths.Clear();
appHost.RestPaths.AddRange(RestPathMap.Values.SelectMany(x => x));
}
public RestPath GetRestPathForRequest(string httpMethod, string pathInfo, ILogger logger)
{
var matchUsingPathParts = RestPath.GetPathPartsForMatching(pathInfo);
List<RestPath> firstMatches;
var yieldedHashMatches = RestPath.GetFirstMatchHashKeys(matchUsingPathParts);
foreach (var potentialHashMatch in yieldedHashMatches)
{
if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches))
{
continue;
}
var bestScore = -1;
foreach (var restPath in firstMatches)
{
var score = restPath.MatchScore(httpMethod, matchUsingPathParts, logger);
if (score > bestScore) bestScore = score;
}
if (bestScore > 0)
{
foreach (var restPath in firstMatches)
{
if (bestScore == restPath.MatchScore(httpMethod, matchUsingPathParts, logger))
return restPath;
}
}
}
var yieldedWildcardMatches = RestPath.GetFirstMatchWildCardHashKeys(matchUsingPathParts);
foreach (var potentialHashMatch in yieldedWildcardMatches)
{
if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches)) continue;
var bestScore = -1;
foreach (var restPath in firstMatches)
{
var score = restPath.MatchScore(httpMethod, matchUsingPathParts, logger);
if (score > bestScore) bestScore = score;
}
if (bestScore > 0)
{
foreach (var restPath in firstMatches)
{
if (bestScore == restPath.MatchScore(httpMethod, matchUsingPathParts, logger))
return restPath;
}
}
}
return null;
}
public async Task<object> Execute(object requestDto, IRequest req)
{
req.Dto = requestDto;
var requestType = requestDto.GetType();
req.OperationName = requestType.Name;
var serviceType = ServiceStackHost.Instance.Metadata.GetServiceTypeByRequest(requestType);
var service = ServiceStackHost.Instance.CreateInstance(serviceType);
//var service = typeFactory.CreateInstance(serviceType);
var serviceRequiresContext = service as IRequiresRequest;
if (serviceRequiresContext != null)
{
serviceRequiresContext.Request = req;
}
if (req.Dto == null) // Don't override existing batched DTO[]
req.Dto = requestDto;
//Executes the service and returns the result
var response = await ServiceExecGeneral.Execute(serviceType, req, service, requestDto, requestType.GetOperationName()).ConfigureAwait(false);
return response;
}
}
}

View File

@@ -1,156 +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.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
namespace ServiceStack.Host
{
public static class ServiceExecExtensions
{
public static IEnumerable<MethodInfo> GetActions(this Type serviceType)
{
foreach (var mi in serviceType.GetRuntimeMethods().Where(i => i.IsPublic && !i.IsStatic))
{
if (mi.GetParameters().Length != 1)
continue;
var actionName = mi.Name.ToUpper();
if (!HttpMethods.AllVerbs.Contains(actionName) && actionName != ActionContext.AnyAction)
continue;
yield return mi;
}
}
}
internal static class ServiceExecGeneral
{
public static Dictionary<string, ActionContext> execMap = new Dictionary<string, ActionContext>();
public static void CreateServiceRunnersFor(Type requestType, List<ActionContext> actions)
{
foreach (var actionCtx in actions)
{
if (execMap.ContainsKey(actionCtx.Id)) continue;
execMap[actionCtx.Id] = actionCtx;
}
}
public static async Task<object> Execute(Type serviceType, IRequest request, object instance, object requestDto, string requestName)
{
var actionName = request.Verb
?? HttpMethods.Post; //MQ Services
ActionContext actionContext;
if (ServiceExecGeneral.execMap.TryGetValue(ActionContext.Key(serviceType, actionName, requestName), out actionContext)
|| ServiceExecGeneral.execMap.TryGetValue(ActionContext.AnyKey(serviceType, requestName), out actionContext))
{
if (actionContext.RequestFilters != null)
{
foreach (var requestFilter in actionContext.RequestFilters)
{
requestFilter.RequestFilter(request, request.Response, requestDto);
if (request.Response.IsClosed) return null;
}
}
var response = actionContext.ServiceAction(instance, requestDto);
var taskResponse = response as Task;
if (taskResponse != null)
{
await taskResponse.ConfigureAwait(false);
response = ServiceStackHost.Instance.GetTaskResult(taskResponse, requestName);
}
return response;
}
var expectedMethodName = actionName.Substring(0, 1) + actionName.Substring(1).ToLower();
throw new NotImplementedException(string.Format("Could not find method named {1}({0}) or Any({0}) on Service {2}", requestDto.GetType().GetOperationName(), expectedMethodName, serviceType.GetOperationName()));
}
public static List<ActionContext> Reset(Type serviceType)
{
var actions = new List<ActionContext>();
foreach (var mi in serviceType.GetActions())
{
var actionName = mi.Name.ToUpper();
var args = mi.GetParameters();
var requestType = args[0].ParameterType;
var actionCtx = new ActionContext
{
Id = ActionContext.Key(serviceType, actionName, requestType.GetOperationName())
};
try
{
actionCtx.ServiceAction = CreateExecFn(serviceType, requestType, mi);
}
catch
{
//Potential problems with MONO, using reflection for fallback
actionCtx.ServiceAction = (service, request) =>
mi.Invoke(service, new[] { request });
}
var reqFilters = new List<IHasRequestFilter>();
foreach (var attr in mi.GetCustomAttributes(true))
{
var hasReqFilter = attr as IHasRequestFilter;
if (hasReqFilter != null)
reqFilters.Add(hasReqFilter);
}
if (reqFilters.Count > 0)
actionCtx.RequestFilters = reqFilters.OrderBy(i => i.Priority).ToArray();
actions.Add(actionCtx);
}
return actions;
}
private static ActionInvokerFn CreateExecFn(Type serviceType, Type requestType, MethodInfo mi)
{
var serviceParam = Expression.Parameter(typeof(object), "serviceObj");
var serviceStrong = Expression.Convert(serviceParam, serviceType);
var requestDtoParam = Expression.Parameter(typeof(object), "requestDto");
var requestDtoStrong = Expression.Convert(requestDtoParam, requestType);
Expression callExecute = Expression.Call(
serviceStrong, mi, requestDtoStrong);
if (mi.ReturnType != typeof(void))
{
var executeFunc = Expression.Lambda<ActionInvokerFn>
(callExecute, serviceParam, requestDtoParam).Compile();
return executeFunc;
}
else
{
var executeFunc = Expression.Lambda<VoidActionInvokerFn>
(callExecute, serviceParam, requestDtoParam).Compile();
return (service, request) =>
{
executeFunc(service, request);
return null;
};
}
}
}
}

View File

@@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
namespace ServiceStack.Host
{
public class ServiceMetadata
{
public ServiceMetadata()
{
this.OperationsMap = new Dictionary<Type, Type>();
}
public Dictionary<Type, Type> OperationsMap { get; protected set; }
public void Add(Type serviceType, Type requestType, Type responseType)
{
this.OperationsMap[requestType] = serviceType;
}
public Type GetServiceTypeByRequest(Type requestType)
{
Type serviceType;
OperationsMap.TryGetValue(requestType, out serviceType);
return serviceType;
}
}
}

View File

@@ -1,41 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Services;
using ServiceStack.Host;
namespace ServiceStack
{
public class HttpHandlerFactory
{
// Entry point for HttpListener
public static RestHandler GetHandler(IHttpRequest httpReq, ILogger logger)
{
var pathInfo = httpReq.PathInfo;
var pathParts = pathInfo.TrimStart('/').Split('/');
if (pathParts.Length == 0)
{
logger.Error("Path parts empty for PathInfo: {0}, Url: {1}", pathInfo, httpReq.RawUrl);
return null;
}
string contentType;
var restPath = RestHandler.FindMatchingRestPath(httpReq.HttpMethod, pathInfo, logger, out contentType);
if (restPath != null)
{
return new RestHandler
{
RestPath = restPath,
RequestName = restPath.RequestType.GetOperationName(),
ResponseContentType = contentType
};
}
logger.Error("Could not find handler for {0}", pathInfo);
return null;
}
}
}

View File

@@ -1,127 +0,0 @@
using System;
using System.Collections.Generic;
using MediaBrowser.Model.Services;
using ServiceStack.Host;
namespace ServiceStack
{
public static class HttpRequestExtensions
{
/**
*
Input: http://localhost:96/Cambia3/Temp/Test.aspx/path/info?q=item#fragment
Some HttpRequest path and URL properties:
Request.ApplicationPath: /Cambia3
Request.CurrentExecutionFilePath: /Cambia3/Temp/Test.aspx
Request.FilePath: /Cambia3/Temp/Test.aspx
Request.Path: /Cambia3/Temp/Test.aspx/path/info
Request.PathInfo: /path/info
Request.PhysicalApplicationPath: D:\Inetpub\wwwroot\CambiaWeb\Cambia3\
Request.QueryString: /Cambia3/Temp/Test.aspx/path/info?query=arg
Request.Url.AbsolutePath: /Cambia3/Temp/Test.aspx/path/info
Request.Url.AbsoluteUri: http://localhost:96/Cambia3/Temp/Test.aspx/path/info?query=arg
Request.Url.Fragment:
Request.Url.Host: localhost
Request.Url.LocalPath: /Cambia3/Temp/Test.aspx/path/info
Request.Url.PathAndQuery: /Cambia3/Temp/Test.aspx/path/info?query=arg
Request.Url.Port: 96
Request.Url.Query: ?query=arg
Request.Url.Scheme: http
Request.Url.Segments: /
Cambia3/
Temp/
Test.aspx/
path/
info
* */
/// <summary>
/// Duplicate Params are given a unique key by appending a #1 suffix
/// </summary>
public static Dictionary<string, string> GetRequestParams(this IRequest request)
{
var map = new Dictionary<string, string>();
foreach (var name in request.QueryString.Keys)
{
if (name == null) continue; //thank you ASP.NET
var values = request.QueryString.GetValues(name);
if (values.Length == 1)
{
map[name] = values[0];
}
else
{
for (var i = 0; i < values.Length; i++)
{
map[name + (i == 0 ? "" : "#" + i)] = values[i];
}
}
}
if ((request.Verb == HttpMethods.Post || request.Verb == HttpMethods.Put)
&& request.FormData != null)
{
foreach (var name in request.FormData.Keys)
{
if (name == null) continue; //thank you ASP.NET
var values = request.FormData.GetValues(name);
if (values.Length == 1)
{
map[name] = values[0];
}
else
{
for (var i = 0; i < values.Length; i++)
{
map[name + (i == 0 ? "" : "#" + i)] = values[i];
}
}
}
}
return map;
}
/// <summary>
/// Duplicate params have their values joined together in a comma-delimited string
/// </summary>
public static Dictionary<string, string> GetFlattenedRequestParams(this IRequest request)
{
var map = new Dictionary<string, string>();
foreach (var name in request.QueryString.Keys)
{
if (name == null) continue; //thank you ASP.NET
map[name] = request.QueryString[name];
}
if ((request.Verb == HttpMethods.Post || request.Verb == HttpMethods.Put)
&& request.FormData != null)
{
foreach (var name in request.FormData.Keys)
{
if (name == null) continue; //thank you ASP.NET
map[name] = request.FormData[name];
}
}
return map;
}
public static void SetRoute(this IRequest req, RestPath route)
{
req.Items["__route"] = route;
}
public static RestPath GetRoute(this IRequest req)
{
object route;
req.Items.TryGetValue("__route", out route);
return route as RestPath;
}
}
}

View File

@@ -1,190 +0,0 @@
//Copyright (c) Service Stack LLC. All Rights Reserved.
//License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt
using System;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using MediaBrowser.Model.Services;
using ServiceStack.Host;
namespace ServiceStack
{
public static class HttpResponseExtensionsInternal
{
public static async Task<bool> WriteToOutputStream(IResponse response, object result)
{
var asyncStreamWriter = result as IAsyncStreamWriter;
if (asyncStreamWriter != null)
{
await asyncStreamWriter.WriteToAsync(response.OutputStream, CancellationToken.None).ConfigureAwait(false);
return true;
}
var streamWriter = result as IStreamWriter;
if (streamWriter != null)
{
streamWriter.WriteTo(response.OutputStream);
return true;
}
var stream = result as Stream;
if (stream != null)
{
using (stream)
{
await stream.CopyToAsync(response.OutputStream).ConfigureAwait(false);
return true;
}
}
var bytes = result as byte[];
if (bytes != null)
{
response.ContentType = "application/octet-stream";
response.SetContentLength(bytes.Length);
await response.OutputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
return true;
}
return false;
}
/// <summary>
/// End a ServiceStack Request with no content
/// </summary>
public static void EndRequestWithNoContent(this IResponse httpRes)
{
if (httpRes.StatusCode == (int)HttpStatusCode.OK)
{
httpRes.StatusCode = (int)HttpStatusCode.NoContent;
}
httpRes.SetContentLength(0);
}
public static Task WriteToResponse(this IResponse httpRes, IRequest httpReq, object result)
{
if (result == null)
{
httpRes.EndRequestWithNoContent();
return Task.FromResult(true);
}
var httpResult = result as IHttpResult;
if (httpResult != null)
{
httpResult.RequestContext = httpReq;
httpReq.ResponseContentType = httpResult.ContentType ?? httpReq.ResponseContentType;
return httpRes.WriteToResponseInternal(httpResult, httpReq);
}
return httpRes.WriteToResponseInternal(result, httpReq);
}
/// <summary>
/// Writes to response.
/// Response headers are customizable by implementing IHasHeaders an returning Dictionary of Http headers.
/// </summary>
/// <param name="response">The response.</param>
/// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param>
/// <param name="request">The serialization context.</param>
/// <returns></returns>
private static async Task WriteToResponseInternal(this IResponse response, object result, IRequest request)
{
var defaultContentType = request.ResponseContentType;
var httpResult = result as IHttpResult;
if (httpResult != null)
{
if (httpResult.RequestContext == null)
httpResult.RequestContext = request;
response.StatusCode = httpResult.Status;
response.StatusDescription = httpResult.StatusCode.ToString();
if (string.IsNullOrEmpty(httpResult.ContentType))
{
httpResult.ContentType = defaultContentType;
}
response.ContentType = httpResult.ContentType;
if (httpResult.Cookies != null)
{
var httpRes = response as IHttpResponse;
if (httpRes != null)
{
foreach (var cookie in httpResult.Cookies)
{
httpRes.SetCookie(cookie);
}
}
}
}
var responseOptions = result as IHasHeaders;
if (responseOptions != null)
{
foreach (var responseHeaders in responseOptions.Headers)
{
if (string.Equals(responseHeaders.Key, "Content-Length", StringComparison.OrdinalIgnoreCase))
{
response.SetContentLength(long.Parse(responseHeaders.Value));
continue;
}
response.AddHeader(responseHeaders.Key, responseHeaders.Value);
}
}
//ContentType='text/html' is the default for a HttpResponse
//Do not override if another has been set
if (response.ContentType == null || response.ContentType == "text/html")
{
response.ContentType = defaultContentType;
}
if (new HashSet<string> { "application/json", }.Contains(response.ContentType))
{
response.ContentType += "; charset=utf-8";
}
var writeToOutputStreamResult = await WriteToOutputStream(response, result).ConfigureAwait(false);
if (writeToOutputStreamResult)
{
return;
}
var responseText = result as string;
if (responseText != null)
{
var bytes = Encoding.UTF8.GetBytes(responseText);
response.SetContentLength(bytes.Length);
await response.OutputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
return;
}
await WriteObject(request, result, response).ConfigureAwait(false);
}
public static async Task WriteObject(IRequest request, object result, IResponse response)
{
var contentType = request.ResponseContentType;
var serializer = ContentTypes.GetStreamSerializer(contentType);
using (var ms = new MemoryStream())
{
serializer(result, ms);
ms.Position = 0;
response.SetContentLength(ms.Length);
await ms.CopyToAsync(response.OutputStream).ConfigureAwait(false);
}
//serializer(result, outputStream);
}
}
}

View File

@@ -1,61 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
using ServiceStack.Host;
namespace ServiceStack
{
public class HttpResult
: IHttpResult, IAsyncStreamWriter
{
public object Response { get; set; }
public HttpResult(object response, string contentType, HttpStatusCode statusCode)
{
this.Headers = new Dictionary<string, string>();
this.Cookies = new List<Cookie>();
this.Response = response;
this.ContentType = contentType;
this.StatusCode = statusCode;
}
public string ContentType { get; set; }
public IDictionary<string, string> Headers { get; private set; }
public List<Cookie> Cookies { get; private set; }
public int Status { get; set; }
public HttpStatusCode StatusCode
{
get { return (HttpStatusCode)Status; }
set { Status = (int)value; }
}
public IRequest RequestContext { get; set; }
public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken)
{
var response = RequestContext != null ? RequestContext.Response : null;
var bytesResponse = this.Response as byte[];
if (bytesResponse != null)
{
if (response != null)
response.SetContentLength(bytesResponse.Length);
await responseStream.WriteAsync(bytesResponse, 0, bytesResponse.Length).ConfigureAwait(false);
return;
}
await HttpResponseExtensionsInternal.WriteObject(this.RequestContext, this.Response, response).ConfigureAwait(false);
}
}
}

View File

@@ -1,34 +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;
namespace ServiceStack
{
internal static class HttpMethods
{
static readonly string[] allVerbs = new[] {
"OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT", // RFC 2616
"PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK", // RFC 2518
"VERSION-CONTROL", "REPORT", "CHECKOUT", "CHECKIN", "UNCHECKOUT",
"MKWORKSPACE", "UPDATE", "LABEL", "MERGE", "BASELINE-CONTROL", "MKACTIVITY", // RFC 3253
"ORDERPATCH", // RFC 3648
"ACL", // RFC 3744
"PATCH", // https://datatracker.ietf.org/doc/draft-dusseault-http-patch/
"SEARCH", // https://datatracker.ietf.org/doc/draft-reschke-webdav-search/
"BCOPY", "BDELETE", "BMOVE", "BPROPFIND", "BPROPPATCH", "NOTIFY",
"POLL", "SUBSCRIBE", "UNSUBSCRIBE" //MS Exchange WebDav: http://msdn.microsoft.com/en-us/library/aa142917.aspx
};
public static HashSet<string> AllVerbs = new HashSet<string>(allVerbs);
public const string Get = "GET";
public const string Put = "PUT";
public const string Post = "POST";
public const string Delete = "DELETE";
public const string Options = "OPTIONS";
public const string Head = "HEAD";
public const string Patch = "PATCH";
}
}

View File

@@ -3,26 +3,11 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace ServiceStack
{
public static class ReflectionExtensions
{
public static bool IsInstanceOf(this Type type, Type thisOrBaseType)
{
while (type != null)
{
if (type == thisOrBaseType)
return true;
type = type.BaseType();
}
return false;
}
public static Type FirstGenericType(this Type type)
{
while (type != null)
@@ -54,44 +39,6 @@ namespace ServiceStack
return null;
}
public static PropertyInfo[] GetAllProperties(this Type type)
{
if (type.IsInterface())
{
var propertyInfos = new List<PropertyInfo>();
var considered = new List<Type>();
var queue = new Queue<Type>();
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.GetTypesProperties();
var newPropertyInfos = typeProperties
.Where(x => !propertyInfos.Contains(x));
propertyInfos.InsertRange(0, newPropertyInfos);
}
return propertyInfos.ToArray();
}
return type.GetTypesProperties()
.Where(t => t.GetIndexParameters().Length == 0) // ignore indexed properties
.ToArray();
}
public static PropertyInfo[] GetPublicProperties(this Type type)
{
if (type.IsInterface())
@@ -139,9 +86,7 @@ namespace ServiceStack
public static PropertyInfo[] GetSerializableProperties(this Type type)
{
var properties = type.IsDto()
? type.GetAllProperties()
: type.GetPublicProperties();
var properties = type.GetPublicProperties();
return properties.OnlySerializableProperties(type);
}
@@ -150,14 +95,7 @@ namespace ServiceStack
public static PropertyInfo[] OnlySerializableProperties(this PropertyInfo[] properties, Type type = null)
{
var isDto = type.IsDto();
var readableProperties = properties.Where(x => x.PropertyGetMethod(nonPublic: isDto) != null);
if (isDto)
{
return readableProperties.Where(attr =>
attr.HasAttribute<DataMemberAttribute>()).ToArray();
}
var readableProperties = properties.Where(x => x.PropertyGetMethod(nonPublic: false) != null);
// else return those properties that are not decorated with IgnoreDataMember
return readableProperties
@@ -206,36 +144,6 @@ namespace ServiceStack
return pis.ToArray();
}
internal static PropertyInfo[] GetTypesProperties(this Type subType)
{
var pis = new List<PropertyInfo>();
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 bool HasAttribute<T>(this Type type)
{
return type.AllAttributes().Any(x => x.GetType() == typeof(T));
}
public static bool HasAttribute<T>(this PropertyInfo pi)
{
return pi.AllAttributes().Any(x => x.GetType() == typeof(T));
}
public static bool IsDto(this Type type)
{
if (type == null)
return false;
return type.HasAttribute<DataContractAttribute>();
}
public static MethodInfo PropertyGetMethod(this PropertyInfo pi, bool nonPublic = false)
{
return pi.GetMethod;
@@ -246,25 +154,15 @@ namespace ServiceStack
return propertyInfo.GetCustomAttributes(true).ToArray();
}
public static object[] AllAttributes(this PropertyInfo propertyInfo, Type attrType)
{
return propertyInfo.GetCustomAttributes(true).Where(x => attrType.IsInstanceOf(x.GetType())).ToArray();
}
public static object[] AllAttributes(this Type type)
{
return type.GetTypeInfo().GetCustomAttributes(true).ToArray();
}
public static TAttr[] AllAttributes<TAttr>(this PropertyInfo pi)
{
return pi.AllAttributes(typeof(TAttr)).Cast<TAttr>().ToArray();
}
public static TAttr[] AllAttributes<TAttr>(this Type type)
public static List<TAttr> AllAttributes<TAttr>(this Type type)
where TAttr : Attribute
{
return type.GetTypeInfo().GetCustomAttributes<TAttr>(true).ToArray();
return type.GetTypeInfo().GetCustomAttributes<TAttr>(true).ToList();
}
}
}

View File

@@ -1,12 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using MediaBrowser.Model.Logging;
using ServiceStack.Serialization;
namespace ServiceStack.Host
namespace ServiceStack
{
public class RestPath
{
@@ -50,7 +49,7 @@ namespace ServiceStack.Host
get
{
return allowsAllVerbs
? new[] { ActionContext.AnyAction }
? new[] { "ANY" }
: AllowedVerbs.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
}
}

View File

@@ -69,24 +69,11 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Compile Include="HttpUtils.cs" />
<Compile Include="Host\ContentTypes.cs" />
<Compile Include="ReflectionExtensions.cs" />
<Compile Include="StringMapTypeDeserializer.cs" />
<Compile Include="HttpResult.cs" />
<Compile Include="ServiceStackHost.cs" />
<Compile Include="ServiceStackHost.Runtime.cs" />
<Compile Include="Host\ServiceExec.cs" />
<Compile Include="UrlExtensions.cs" />
<Compile Include="Host\ActionContext.cs" />
<Compile Include="HttpRequestExtensions.cs" />
<Compile Include="Host\RestPath.cs" />
<Compile Include="Host\ServiceController.cs" />
<Compile Include="Host\ServiceMetadata.cs" />
<Compile Include="Host\RestHandler.cs" />
<Compile Include="HttpResponseExtensionsInternal.cs" />
<Compile Include="HttpHandlerFactory.cs" />
<Compile Include="FilterAttributeCache.cs" />
<Compile Include="RestPath.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,57 +0,0 @@
// Copyright (c) Service Stack LLC. All Rights Reserved.
// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt
using MediaBrowser.Model.Services;
using ServiceStack.Support.WebHost;
namespace ServiceStack
{
public abstract partial class ServiceStackHost
{
/// <summary>
/// Applies the request filters. Returns whether or not the request has been handled
/// and no more processing should be done.
/// </summary>
/// <returns></returns>
public virtual void ApplyRequestFilters(IRequest req, IResponse res, object requestDto)
{
//Exec all RequestFilter attributes with Priority < 0
var attributes = FilterAttributeCache.GetRequestFilterAttributes(requestDto.GetType());
var i = 0;
for (; i < attributes.Length && attributes[i].Priority < 0; i++)
{
var attribute = attributes[i];
attribute.RequestFilter(req, res, requestDto);
}
//Exec global filters
foreach (var requestFilter in GlobalRequestFilters)
{
requestFilter(req, res, requestDto);
}
//Exec remaining RequestFilter attributes with Priority >= 0
for (; i < attributes.Length && attributes[i].Priority >= 0; i++)
{
var attribute = attributes[i];
attribute.RequestFilter(req, res, requestDto);
}
}
/// <summary>
/// Applies the response filters. Returns whether or not the request has been handled
/// and no more processing should be done.
/// </summary>
/// <returns></returns>
public virtual void ApplyResponseFilters(IRequest req, IResponse res, object response)
{
//Exec global filters
foreach (var responseFilter in GlobalResponseFilters)
{
responseFilter(req, res, response);
}
}
}
}

View File

@@ -6,71 +6,24 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Services;
using ServiceStack.Host;
namespace ServiceStack
{
public abstract partial class ServiceStackHost : IDisposable
public abstract class ServiceStackHost : IDisposable
{
public static ServiceStackHost Instance { get; protected set; }
protected ServiceStackHost(string serviceName)
protected ServiceStackHost()
{
ServiceName = serviceName;
ServiceController = CreateServiceController();
RestPaths = new List<RestPath>();
Metadata = new ServiceMetadata();
GlobalRequestFilters = new List<Action<IRequest, IResponse, object>>();
GlobalResponseFilters = new List<Action<IRequest, IResponse, object>>();
}
public abstract void Configure();
public abstract object CreateInstance(Type type);
protected abstract ServiceController CreateServiceController();
public virtual ServiceStackHost Init()
{
Instance = this;
ServiceController.Init();
Configure();
ServiceController.AfterInit();
return this;
}
public virtual ServiceStackHost Start(string urlBase)
{
throw new NotImplementedException("Start(listeningAtUrlBase) is not supported by this AppHost");
}
public string ServiceName { get; set; }
public ServiceMetadata Metadata { get; set; }
public ServiceController ServiceController { get; set; }
public List<RestPath> RestPaths = new List<RestPath>();
public List<Action<IRequest, IResponse, object>> GlobalRequestFilters { get; set; }
public List<Action<IRequest, IResponse, object>> GlobalResponseFilters { get; set; }
public abstract T TryResolve<T>();
public abstract T Resolve<T>();
public virtual MediaBrowser.Model.Services.RouteAttribute[] GetRouteAttributes(Type requestType)
{
return requestType.AllAttributes<MediaBrowser.Model.Services.RouteAttribute>();
}
public abstract object GetTaskResult(Task task, string requestName);
public abstract RouteAttribute[] GetRouteAttributes(Type requestType);
public abstract Func<string, object> GetParseFn(Type propertyType);
@@ -85,20 +38,5 @@ namespace ServiceStack
Instance = null;
}
protected abstract ILogger Logger
{
get;
}
public void OnLogError(Type type, string message)
{
Logger.Error(message);
}
public void OnLogError(Type type, string message, Exception ex)
{
Logger.ErrorException(message, ex);
}
}
}

View File

@@ -48,11 +48,6 @@ namespace ServiceStack.Serialization
var propertyParseStringFn = GetParseFn(propertyType);
var propertySerializer = new PropertySerializerEntry(propertySetFn, propertyParseStringFn) { PropertyType = propertyType };
var attr = propertyInfo.AllAttributes<DataMemberAttribute>().FirstOrDefault();
if (attr != null && attr.Name != null)
{
propertySetterMap[attr.Name] = propertySerializer;
}
propertySetterMap[propertyInfo.Name] = propertySerializer;
}
}