...或“如何根据URI确定调用哪个WCF方法?”
在WCF服务中,假设调用了一个方法,并且我有用于调用它的URI。如何获取有关URI映射到的WCF端点,方法,参数等的信息?
[OperationContract]
[WebGet(UriTemplate = "/People/{id}")]
public Person GetPersonByID(int id)
{
//...
}
例如,如果URI是:GET http://localhost/Contacts.svc/People/1
,我想获取此信息:服务名称(服务),方法(GetPersonByID),参数(PersonID = 1)。关键是能够侦听请求,然后提取请求的详细信息,以便跟踪API调用。
该服务通过http托管。在.Net缓存可以启动之前,此信息是必需的,因此可以跟踪每个调用(无论是否缓存)。这可能意味着在HttpApplication.BeginRequest
内执行此操作。
仅供参考我希望不使用反射。我想使用WCF用来确定这个的相同方法。例如。 MagicEndPointFinder.Resolve(uri)
答案 0 :(得分:0)
这是我最终做的事情,如果有更清洁的方式仍然感兴趣!
private static class OperationContractResolver
{
private static readonly Dictionary<string, MethodInfo> RegularExpressionsByMethod = null;
static OperationContractResolver()
{
OperationContractResolver.RegularExpressionsByMethod = new Dictionary<string, MethodInfo>();
foreach (MethodInfo method in typeof(IREST).GetMethods())
{
WebGetAttribute attribute = (WebGetAttribute)method.GetCustomAttributes(typeof(WebGetAttribute), false).FirstOrDefault();
if (attribute != null)
{
string regex = attribute.UriTemplate;
//Escape question marks. Looks strange but replaces a literal "?" with "\?".
regex = Regex.Replace(regex, @"\?", @"\?");
//Replace all parameters.
regex = Regex.Replace(regex, @"\{[^/$\?]+?}", @"[^/$\?]+?");
//Add it to the dictionary.
OperationContractResolver.RegularExpressionsByMethod.Add(regex, method);
}
}
}
public static string ExtractApiCallInfo(string relativeUri)
{
foreach (string regex in OperationContractResolver.RegularExpressionsByMethod.Keys)
if (Regex.IsMatch(relativeUri, regex, RegexOptions.IgnoreCase))
return OperationContractResolver.RegularExpressionsByMethod[regex].Name;
return null;
}
}
private static void TrackSoapApiCallInfo(HttpContext context)
{
string filePath = Path.GetTempFileName();
string title = null;
//Save the request content. (Unfortunately it can't be written to a stream directly.)
context.Request.SaveAs(filePath, false);
//If the title can't be extracted then it's not an API method call, ignore it.
try
{
//Read the name of the first element within the SOAP body.
using (XmlReader reader = XmlReader.Create(filePath))
{
if (!reader.EOF)
{
XmlNamespaceManager nsManager = new XmlNamespaceManager(reader.NameTable);
XDocument document = XDocument.Load(reader);
//Need to add the SOAP Envelope namespace to the name table.
nsManager.AddNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");
title = document.XPathSelectElement("s:Envelope/s:Body", nsManager).Elements().First().Name.LocalName;
}
}
//Delete the temporary file.
File.Delete(filePath);
}
catch { }
//Track the page view.
}