make controller project portable

This commit is contained in:
Luke Pulverenti
2016-10-25 15:02:04 -04:00
parent edbe28d9fc
commit ef6b90b8e6
441 changed files with 21169 additions and 18588 deletions

View File

@@ -0,0 +1,61 @@
using System;
namespace MediaBrowser.Model.Services
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public class ApiMemberAttribute : Attribute
{
/// <summary>
/// Gets or sets verb to which applies attribute. By default applies to all verbs.
/// </summary>
public string Verb { get; set; }
/// <summary>
/// Gets or sets parameter type: It can be only one of the following: path, query, body, form, or header.
/// </summary>
public string ParameterType { get; set; }
/// <summary>
/// Gets or sets unique name for the parameter. Each name must be unique, even if they are associated with different paramType values.
/// </summary>
/// <remarks>
/// <para>
/// Other notes on the name field:
/// If paramType is body, the name is used only for UI and codegeneration.
/// If paramType is path, the name field must correspond to the associated path segment from the path field in the api object.
/// If paramType is query, the name field corresponds to the query param name.
/// </para>
/// </remarks>
public string Name { get; set; }
/// <summary>
/// Gets or sets the human-readable description for the parameter.
/// </summary>
public string Description { get; set; }
/// <summary>
/// For path, query, and header paramTypes, this field must be a primitive. For body, this can be a complex or container datatype.
/// </summary>
public string DataType { get; set; }
/// <summary>
/// For path, this is always true. Otherwise, this field tells the client whether or not the field must be supplied.
/// </summary>
public bool IsRequired { get; set; }
/// <summary>
/// For query params, this specifies that a comma-separated list of values can be passed to the API. For path and body types, this field cannot be true.
/// </summary>
public bool AllowMultiple { get; set; }
/// <summary>
/// Gets or sets route to which applies attribute, matches using StartsWith. By default applies to all routes.
/// </summary>
public string Route { get; set; }
/// <summary>
/// Whether to exclude this property from being included in the ModelSchema
/// </summary>
public bool ExcludeInSchema { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Model.Services
{
public interface IAsyncStreamWriter
{
Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken);
}
}

View File

@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace MediaBrowser.Model.Services
{
public interface IHasHeaders
{
IDictionary<string, string> Headers { get; }
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MediaBrowser.Model.Services
{
public interface IHasRequestFilter
{
/// <summary>
/// Order in which Request Filters are executed.
/// &lt;0 Executed before global request filters
/// &gt;0 Executed after global request filters
/// </summary>
int Priority { get; }
/// <summary>
/// The request filter is executed before the service.
/// </summary>
/// <param name="req">The http request wrapper</param>
/// <param name="res">The http response wrapper</param>
/// <param name="requestDto">The request DTO</param>
void RequestFilter(IRequest req, IResponse res, object requestDto);
/// <summary>
/// A new shallow copy of this filter is used on every request.
/// </summary>
/// <returns></returns>
IHasRequestFilter Copy();
}
}

View File

@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MediaBrowser.Model.Services
{
public interface IHttpRequest : IRequest
{
/// <summary>
/// The HttpResponse
/// </summary>
IHttpResponse HttpResponse { get; }
/// <summary>
/// The HTTP Verb
/// </summary>
string HttpMethod { get; }
/// <summary>
/// The IP Address of the X-Forwarded-For header, null if null or empty
/// </summary>
string XForwardedFor { get; }
/// <summary>
/// The Port number of the X-Forwarded-Port header, null if null or empty
/// </summary>
int? XForwardedPort { get; }
/// <summary>
/// The http or https scheme of the X-Forwarded-Proto header, null if null or empty
/// </summary>
string XForwardedProtocol { get; }
/// <summary>
/// The value of the X-Real-IP header, null if null or empty
/// </summary>
string XRealIp { get; }
/// <summary>
/// The value of the Accept HTTP Request Header
/// </summary>
string Accept { get; }
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace MediaBrowser.Model.Services
{
public interface IHttpResponse : IResponse
{
//ICookies Cookies { get; }
/// <summary>
/// Adds a new Set-Cookie instruction to Response
/// </summary>
/// <param name="cookie"></param>
void SetCookie(Cookie cookie);
/// <summary>
/// Removes all pending Set-Cookie instructions
/// </summary>
void ClearCookies();
}
}

View File

@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
namespace MediaBrowser.Model.Services
{
public interface IRequest
{
/// <summary>
/// The underlying ASP.NET or HttpListener HttpRequest
/// </summary>
object OriginalRequest { get; }
IResponse Response { get; }
/// <summary>
/// The name of the service being called (e.g. Request DTO Name)
/// </summary>
string OperationName { get; set; }
/// <summary>
/// The Verb / HttpMethod or Action for this request
/// </summary>
string Verb { get; }
/// <summary>
/// The Request DTO, after it has been deserialized.
/// </summary>
object Dto { get; set; }
/// <summary>
/// The request ContentType
/// </summary>
string ContentType { get; }
bool IsLocal { get; }
string UserAgent { get; }
IDictionary<string, Cookie> Cookies { get; }
/// <summary>
/// The expected Response ContentType for this request
/// </summary>
string ResponseContentType { get; set; }
/// <summary>
/// Whether the ResponseContentType has been explicitly overrided or whether it was just the default
/// </summary>
bool HasExplicitResponseContentType { get; }
/// <summary>
/// Attach any data to this request that all filters and services can access.
/// </summary>
Dictionary<string, object> Items { get; }
QueryParamCollection Headers { get; }
QueryParamCollection QueryString { get; }
QueryParamCollection FormData { get; }
/// <summary>
/// Buffer the Request InputStream so it can be re-read
/// </summary>
bool UseBufferedStream { get; set; }
/// <summary>
/// The entire string contents of Request.InputStream
/// </summary>
/// <returns></returns>
string GetRawBody();
string RawUrl { get; }
string AbsoluteUri { get; }
/// <summary>
/// The Remote Ip as reported by Request.UserHostAddress
/// </summary>
string UserHostAddress { get; }
/// <summary>
/// The Remote Ip as reported by X-Forwarded-For, X-Real-IP or Request.UserHostAddress
/// </summary>
string RemoteIp { get; }
/// <summary>
/// The value of the Authorization Header used to send the Api Key, null if not available
/// </summary>
string Authorization { get; }
/// <summary>
/// e.g. is https or not
/// </summary>
bool IsSecureConnection { get; }
string[] AcceptTypes { get; }
string PathInfo { get; }
Stream InputStream { get; }
long ContentLength { get; }
/// <summary>
/// Access to the multi-part/formdata files posted on this request
/// </summary>
IHttpFile[] Files { get; }
/// <summary>
/// The value of the Referrer, null if not available
/// </summary>
Uri UrlReferrer { get; }
}
public interface IHttpFile
{
string Name { get; }
string FileName { get; }
long ContentLength { get; }
string ContentType { get; }
Stream InputStream { get; }
}
public interface IRequiresRequest
{
IRequest Request { get; set; }
}
public interface IResponse
{
/// <summary>
/// The underlying ASP.NET or HttpListener HttpResponse
/// </summary>
object OriginalResponse { get; }
IRequest Request { get; }
int StatusCode { get; set; }
string StatusDescription { get; set; }
string ContentType { get; set; }
void AddHeader(string name, string value);
string GetHeader(string name);
void Redirect(string url);
Stream OutputStream { get; }
/// <summary>
/// The Response DTO
/// </summary>
object Dto { get; set; }
/// <summary>
/// Write once to the Response Stream then close it.
/// </summary>
/// <param name="text"></param>
void Write(string text);
/// <summary>
/// Buffer the Response OutputStream so it can be written in 1 batch
/// </summary>
bool UseBufferedStream { get; set; }
/// <summary>
/// Signal that this response has been handled and no more processing should be done.
/// When used in a request or response filter, no more filters or processing is done on this request.
/// </summary>
void Close();
/// <summary>
/// Calls Response.End() on ASP.NET HttpResponse otherwise is an alias for Close().
/// Useful when you want to prevent ASP.NET to provide it's own custom error page.
/// </summary>
void End();
/// <summary>
/// Response.Flush() and OutputStream.Flush() seem to have different behaviour in ASP.NET
/// </summary>
void Flush();
/// <summary>
/// Gets a value indicating whether this instance is closed.
/// </summary>
bool IsClosed { get; }
void SetContentLength(long contentLength);
bool KeepAlive { get; set; }
//Add Metadata to Response
Dictionary<string, object> Items { get; }
}
}

View File

@@ -0,0 +1,12 @@
using System.IO;
namespace MediaBrowser.Model.Services
{
public interface IRequiresRequestStream
{
/// <summary>
/// The raw Http Request Input Stream
/// </summary>
Stream RequestStream { get; set; }
}
}

View File

@@ -0,0 +1,12 @@

namespace MediaBrowser.Model.Services
{
// marker interface
public interface IService
{
}
public interface IReturn { }
public interface IReturn<T> : IReturn { }
public interface IReturnVoid : IReturn { }
}

View File

@@ -0,0 +1,9 @@
using System.IO;
namespace MediaBrowser.Model.Services
{
public interface IStreamWriter
{
void WriteTo(Stream responseStream);
}
}

View File

@@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Dto;
namespace MediaBrowser.Model.Services
{
public class QueryParamCollection : List<NameValuePair>
{
public QueryParamCollection()
{
}
public QueryParamCollection(IDictionary<string, string> headers)
{
foreach (var pair in headers)
{
Add(pair.Key, pair.Value);
}
}
private StringComparison GetStringComparison()
{
return StringComparison.OrdinalIgnoreCase;
}
private StringComparer GetStringComparer()
{
return StringComparer.OrdinalIgnoreCase;
}
/// <summary>
/// Adds a new query parameter.
/// </summary>
public void Add(string key, string value)
{
Add(new NameValuePair(key, value));
}
public void Set(string key, string value)
{
if (string.IsNullOrWhiteSpace(value))
{
var stringComparison = GetStringComparison();
var parameters = this.Where(p => string.Equals(key, p.Name, stringComparison)).ToArray();
foreach (var p in parameters)
{
Remove(p);
}
return;
}
foreach (var pair in this)
{
var stringComparison = GetStringComparison();
if (string.Equals(key, pair.Name, stringComparison))
{
pair.Value = value;
return;
}
}
Add(key, value);
}
/// <summary>
/// True if the collection contains a query parameter with the given name.
/// </summary>
public bool ContainsKey(string name)
{
return this.Any(p => p.Name == name);
}
/// <summary>
/// Removes all parameters of the given name.
/// </summary>
/// <returns>The number of parameters that were removed</returns>
/// <exception cref="ArgumentNullException"><paramref name="name" /> is null.</exception>
public int Remove(string name)
{
return RemoveAll(p => p.Name == name);
}
public string Get(string name)
{
return GetValues(name).FirstOrDefault();
}
public string[] GetValues(string name)
{
var stringComparison = GetStringComparison();
return this.Where(p => string.Equals(p.Name, name, stringComparison)).Select(p => p.Value).ToArray();
}
public Dictionary<string, string> ToDictionary()
{
var stringComparer = GetStringComparer();
var headers = new Dictionary<string, string>(stringComparer);
foreach (var pair in this)
{
headers[pair.Name] = pair.Value;
}
return headers;
}
public IEnumerable<string> Keys
{
get { return this.Select(i => i.Name); }
}
/// <summary>
/// Gets or sets a query parameter value by name. A query may contain multiple values of the same name
/// (i.e. "x=1&amp;x=2"), in which case the value is an array, which works for both getting and setting.
/// </summary>
/// <param name="name">The query parameter name</param>
/// <returns>The query parameter value or array of values</returns>
public string this[string name]
{
get { return Get(name); }
set
{
Set(name, value);
//var parameters = this.Where(p => p.Name == name).ToArray();
//var values = new[] { value };
//for (int i = 0; ; i++)
//{
// if (i < parameters.Length && i < values.Length)
// {
// if (values[i] == null)
// Remove(parameters[i]);
// else if (values[i] is NameValuePair)
// this[IndexOf(parameters[i])] = (NameValuePair)values[i];
// else
// parameters[i].Value = values[i];
// }
// else if (i < parameters.Length)
// Remove(parameters[i]);
// else if (i < values.Length)
// {
// if (values[i] != null)
// {
// if (values[i] is NameValuePair)
// Add((NameValuePair)values[i]);
// else
// Add(name, values[i]);
// }
// }
// else
// break;
//}
}
}
}
}

View File

@@ -0,0 +1,144 @@
using System;
namespace MediaBrowser.Model.Services
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class RouteAttribute : Attribute
{
/// <summary>
/// <para>Initializes an instance of the <see cref="RouteAttribute"/> class.</para>
/// </summary>
/// <param name="path">
/// <para>The path template to map to the request. See
/// <see cref="Path">RouteAttribute.Path</see>
/// for details on the correct format.</para>
/// </param>
public RouteAttribute(string path)
: this(path, null)
{
}
/// <summary>
/// <para>Initializes an instance of the <see cref="RouteAttribute"/> class.</para>
/// </summary>
/// <param name="path">
/// <para>The path template to map to the request. See
/// <see cref="Path">RouteAttribute.Path</see>
/// for details on the correct format.</para>
/// </param>
/// <param name="verbs">A comma-delimited list of HTTP verbs supported by the
/// service. If unspecified, all verbs are assumed to be supported.</param>
public RouteAttribute(string path, string verbs)
{
Path = path;
Verbs = verbs;
}
/// <summary>
/// Gets or sets the path template to be mapped to the request.
/// </summary>
/// <value>
/// A <see cref="String"/> value providing the path mapped to
/// the request. Never <see langword="null"/>.
/// </value>
/// <remarks>
/// <para>Some examples of valid paths are:</para>
///
/// <list>
/// <item>"/Inventory"</item>
/// <item>"/Inventory/{Category}/{ItemId}"</item>
/// <item>"/Inventory/{ItemPath*}"</item>
/// </list>
///
/// <para>Variables are specified within "{}"
/// brackets. Each variable in the path is mapped to the same-named property
/// on the request DTO. At runtime, ServiceStack will parse the
/// request URL, extract the variable values, instantiate the request DTO,
/// and assign the variable values into the corresponding request properties,
/// prior to passing the request DTO to the service object for processing.</para>
///
/// <para>It is not necessary to specify all request properties as
/// variables in the path. For unspecified properties, callers may provide
/// values in the query string. For example: the URL
/// "http://services/Inventory?Category=Books&amp;ItemId=12345" causes the same
/// request DTO to be processed as "http://services/Inventory/Books/12345",
/// provided that the paths "/Inventory" (which supports the first URL) and
/// "/Inventory/{Category}/{ItemId}" (which supports the second URL)
/// are both mapped to the request DTO.</para>
///
/// <para>Please note that while it is possible to specify property values
/// in the query string, it is generally considered to be less RESTful and
/// less desirable than to specify them as variables in the path. Using the
/// query string to specify property values may also interfere with HTTP
/// caching.</para>
///
/// <para>The final variable in the path may contain a "*" suffix
/// to grab all remaining segments in the path portion of the request URL and assign
/// them to a single property on the request DTO.
/// For example, if the path "/Inventory/{ItemPath*}" is mapped to the request DTO,
/// then the request URL "http://services/Inventory/Books/12345" will result
/// in a request DTO whose ItemPath property contains "Books/12345".
/// You may only specify one such variable in the path, and it must be positioned at
/// the end of the path.</para>
/// </remarks>
public string Path { get; set; }
/// <summary>
/// Gets or sets short summary of what the route does.
/// </summary>
public string Summary { get; set; }
/// <summary>
/// Gets or sets longer text to explain the behaviour of the route.
/// </summary>
public string Notes { get; set; }
/// <summary>
/// Gets or sets a comma-delimited list of HTTP verbs supported by the service, such as
/// "GET,PUT,POST,DELETE".
/// </summary>
/// <value>
/// A <see cref="String"/> providing a comma-delimited list of HTTP verbs supported
/// by the service, <see langword="null"/> or empty if all verbs are supported.
/// </value>
public string Verbs { get; set; }
/// <summary>
/// Used to rank the precedences of route definitions in reverse routing.
/// i.e. Priorities below 0 are auto-generated have less precedence.
/// </summary>
public int Priority { get; set; }
protected bool Equals(RouteAttribute other)
{
return base.Equals(other)
&& string.Equals(Path, other.Path)
&& string.Equals(Summary, other.Summary)
&& string.Equals(Notes, other.Notes)
&& string.Equals(Verbs, other.Verbs)
&& Priority == other.Priority;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((RouteAttribute)obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = base.GetHashCode();
hashCode = (hashCode * 397) ^ (Path != null ? Path.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (Summary != null ? Summary.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (Notes != null ? Notes.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (Verbs != null ? Verbs.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ Priority;
return hashCode;
}
}
}
}