using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.IdentityModel.Claims;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
using System.Text;
using System.Threading.Tasks;
using Nancy;
using Nancy.Bootstrapper;
using Nancy.Cookies;
using Nancy.Extensions;
using Nancy.IO;
using NLog;
using Sony.Filtr.API.Nancy.Config;
namespace Sony.Filtr.API.WCF
{
///
/// Host for running Nancy ontop of WCF.
///
///
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceContract]
public class MyNancyWcfGenericService : IDisposable
{
private readonly INancyEngine engine;
private readonly INancyBootstrapper bootstrapper;
///
/// Initializes a new instance of the class with a default bootstrapper.
///
///
public MyNancyWcfGenericService()
: this(NancyBootstrapperLocator.Bootstrapper)
{
}
///
/// Initializes a new instance of the class, with the provided .
///
///
/// An instance, that should be used to handle the requests.
public MyNancyWcfGenericService(INancyBootstrapper bootstrapper)
{
this.bootstrapper = bootstrapper;
bootstrapper.Initialise();
this.engine = bootstrapper.GetEngine();
}
///
/// Handle an incoming request with Nancy.
///
///
/// The body of the incoming request.
///
/// A instance.
///
[WebInvoke(Method = "*", UriTemplate = "*")]
public Message HandleRequests(Stream requestBody)
{
_logger.Debug("MyNancyWcfGenericService handleRequests");
WebOperationContext current = WebOperationContext.Current;
NancyContext nancyContext = NancyEngineExtensions.HandleRequest(this.engine, CreateNancyRequestFromIncomingWebRequest(current.IncomingRequest, requestBody, OperationContext.Current));
SetNancyResponseToOutgoingWebResponse(current.OutgoingResponse, nancyContext.Response);
_logger.Debug("Kinda done with MyNancyWcfGenericService handleRequests");
return current.CreateStreamResponse((Action)(stream =>
{
nancyContext.Response.Contents(stream);
nancyContext.Dispose();
}), nancyContext.Response.ContentType ?? string.Empty);
}
public void Dispose()
{
this.bootstrapper.Dispose();
}
private static Request CreateNancyRequestFromIncomingWebRequest(IncomingWebRequestContext webRequest, Stream requestBody, OperationContext context)
{
var logger = NLog.LogManager.GetLogger("Argh");
string ip = (string)null;
object obj;
if (OperationContext.Current.IncomingMessageProperties.TryGetValue(RemoteEndpointMessageProperty.Name, out obj))
ip = ((RemoteEndpointMessageProperty)obj).Address;
var relativeUri = GetNancyRelativeUrlFromBaseUrl(webRequest, logger);
long expectedRequestLength = GetExpectedRequestLength(CollectionExtensions.ToDictionary((NameValueCollection)webRequest.Headers));
Url url = new Url()
{
BasePath = webRequest.UriTemplateMatch.BaseUri.AbsolutePath,
Scheme = webRequest.UriTemplateMatch.RequestUri.Scheme,
HostName = webRequest.UriTemplateMatch.BaseUri.Host,
Port = webRequest.UriTemplateMatch.RequestUri.IsDefaultPort ? new int?() : new int?(webRequest.UriTemplateMatch.RequestUri.Port),
Path = "/" + relativeUri,
Query = webRequest.UriTemplateMatch.RequestUri.Query
};
logger.Debug("Url.BasePath" + url.BasePath);
logger.Debug("Url.Scheme" + url.Scheme);
logger.Debug("Url.HostName" + url.HostName);
logger.Debug("Url.Port" + url.Port);
logger.Debug("Url.Path" + url.Path);
logger.Debug("Url.Query" + url.Query);
byte[] certificate = (byte[])null;
if (context.ServiceSecurityContext != null && context.ServiceSecurityContext.AuthorizationContext.ClaimSets.Count > 0)
{
X509CertificateClaimSet certificateClaimSet = Enumerable.FirstOrDefault((IEnumerable)context.ServiceSecurityContext.AuthorizationContext.ClaimSets, (Func)(c => c is X509CertificateClaimSet)) as X509CertificateClaimSet;
if (certificateClaimSet != null)
certificate = certificateClaimSet.X509Certificate.RawData;
}
logger.Debug("Kinda done with CreateNancyRequestFromIncomingWebRequest");
logger.Debug("CreateNancyRequestFromIncomingWebRequest says the url is" + url);
return new Request(webRequest.Method, url, RequestStream.FromStream(requestBody, expectedRequestLength, false), CollectionExtensions.ToDictionary((NameValueCollection)webRequest.Headers), ip, certificate);
}
private static Uri GetNancyRelativeUrlFromBaseUrl(IncomingWebRequestContext webRequest, Logger logger)
{
Uri uri1 = GetUrlAndPathComponents(webRequest.UriTemplateMatch.BaseUri);
if (!uri1.OriginalString.EndsWith("/"))
uri1 = new Uri(uri1.OriginalString + "/");
logger.Debug("CreateNancyRequestFromIncomingWebRequest uri1 " + uri1);
var uriBuilder = new UriBuilder(uri1);
uriBuilder.Host = webRequest.UriTemplateMatch.RequestUri.Host;
Uri uri2 = uriBuilder.Uri.MakeRelativeUri(GetUrlAndPathComponents(webRequest.UriTemplateMatch.RequestUri));
logger.Debug("CreateNancyRequestFromIncomingWebRequest uri2 " + uri2);
return uri2;
}
private static void PrintLogValues(Logger logger, IncomingWebRequestContext webRequest)
{
logger.Debug("PrintLogValues:BasePath: " + webRequest.UriTemplateMatch.BaseUri.AbsolutePath);
logger.Debug("PrintLogValues:Scheme: " + webRequest.UriTemplateMatch.RequestUri.Scheme);
logger.Debug("PrintLogValues:HostName: " + webRequest.UriTemplateMatch.BaseUri.Host);
logger.Debug("PrintLogValues:Port: " + webRequest.UriTemplateMatch.RequestUri.Port);
logger.Debug("PrintLogValues:Path: " + webRequest.UriTemplateMatch.BaseUri.AbsolutePath);
logger.Debug("PrintLogValues:Query: " + webRequest.UriTemplateMatch.RequestUri.Query);
}
private static long GetExpectedRequestLength(IDictionary> incomingHeaders)
{
if (incomingHeaders == null || !incomingHeaders.ContainsKey("Content-Length"))
return 0;
string s = Enumerable.SingleOrDefault(incomingHeaders["Content-Length"]);
long result;
if (s == null || !long.TryParse(s, NumberStyles.Any, (IFormatProvider)CultureInfo.InvariantCulture, out result))
return 0;
return result;
}
private static Uri GetUrlAndPathComponents(Uri uri)
{
return new Uri(uri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.Unescaped));
}
private static void SetNancyResponseToOutgoingWebResponse(OutgoingWebResponseContext webResponse, Response nancyResponse)
{
SetHttpResponseHeaders(webResponse, nancyResponse);
if (nancyResponse.ContentType != null)
webResponse.ContentType = nancyResponse.ContentType;
if (nancyResponse.ReasonPhrase != null)
webResponse.StatusDescription = nancyResponse.ReasonPhrase;
webResponse.StatusCode = (System.Net.HttpStatusCode)nancyResponse.StatusCode;
}
private static void SetHttpResponseHeaders(OutgoingWebResponseContext context, Response response)
{
foreach (KeyValuePair keyValuePair in (IEnumerable>)response.Headers)
context.Headers.Add(keyValuePair.Key, keyValuePair.Value);
foreach (INancyCookie nancyCookie in (IEnumerable)response.Cookies)
context.Headers.Add("Set-Cookie", nancyCookie.ToString());
}
}
}