Asp.net 从HTTP模块获取ASMX Web服务的自定义属性
情况如下: 旧版ASP.NET产品。许多旧的ASMX服务(在其他类型的端点中——ASPX、ASHX等) 我们正在增强一些安全逻辑。部分更改要求定义每个ASMX服务所属的应用程序模块。为此,我们计划使用如下所示的自定义属性Asp.net 从HTTP模块获取ASMX Web服务的自定义属性,asp.net,asmx,httpmodule,Asp.net,Asmx,Httpmodule,情况如下: 旧版ASP.NET产品。许多旧的ASMX服务(在其他类型的端点中——ASPX、ASHX等) 我们正在增强一些安全逻辑。部分更改要求定义每个ASMX服务所属的应用程序模块。为此,我们计划使用如下所示的自定义属性 [AttributeUsage(AttributeTargets.Class)] public class ModuleAssignmentAttribute : Attribute { public Module[] Modules { get; set; }
[AttributeUsage(AttributeTargets.Class)]
public class ModuleAssignmentAttribute : Attribute
{
public Module[] Modules { get; set; }
public ModuleAssignmentAttribute(params Module[] modules)
{
Modules = modules;
}
}
下面是如何将模块应用于ASMX服务的示例
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ModuleAssignment(Module.ApplicationModuleA)]
public class SomeService : System.Web.Services.WebService
{
[WebMethod(true)]
public string GetValue()
{
return "Some Service Value";
}
}
下面的HTTP模块将用于授权访问该服务
公共类MyAuthorizationModule:IHttpModule
{
公共空间处置()
{
//这里有清理代码。
}
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += new EventHandler(OnAuthorizeRequest);
}
public void OnAuthorizeRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Handler == null) return;
Attribute att = Attribute.GetCustomAttribute(HttpContext.Current.Handler.GetType(), typeof(ModuleAssignmentAttribute));
if (att != null)
{
Module[] modules = ((ModuleAssignmentAttribute)att).Modules;
// Simulate getting the user's active role ID
int roleId = 1;
// Simulate performing an authz check
AuthorizationAgent agent = new AuthorizationAgent();
bool authorized = agent.AuthorizeRequest(roleId, modules);
if (!authorized)
{
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.StatusCode = 401;
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
}
}
问题是,对于ASMXWeb服务,HTTP模块中的以下代码行返回null(请注意,这适用于ASPX页面)
在这种情况下,HttpContext.Current.Handler.GetType()的值是“System.Web.Script.Services.ScriptHandlerFactory+HandlerWrapperWithSession”。该类型显然不知道在ASMX服务上定义的自定义属性
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ModuleAssignment(Module.ApplicationModuleA)]
public class SomeService : System.Web.Services.WebService
{
[WebMethod(true)]
public string GetValue()
{
return "Some Service Value";
}
}
关于如何在此场景中从ASMX服务类型获取自定义属性,您有什么想法吗?这里有一个问题的解决方案。需要反思。丑陋而脆弱的代码-如果不需要,我不建议您使用它。我想知道我是否忽略了更优雅的方式
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += new EventHandler(OnAuthorizeRequest);
}
public void OnAuthorizeRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Handler == null) return;
Attribute att = null;
// ScriptHandlerFactory+HandlerWrapperWithSession is the type of handler for ASMX web service calls to web methods that use session.
// This class is internal, so need to do a string comparison here (is there another way?).
if (HttpContext.Current.Handler.GetType().ToString() == "System.Web.Script.Services.ScriptHandlerFactory+HandlerWrapperWithSession")
{
// HandlerWrapperWithSession has a protected field named "_originalHandler" that it inherits from HandlerWrapper.
FieldInfo originalHandlerField = HttpContext.Current.Handler.GetType().GetField("_originalHandler",BindingFlags.NonPublic | BindingFlags.Instance);
object originalHandler = originalHandlerField.GetValue(HttpContext.Current.Handler);
// The _originalHandler value is an instance of SyncSessionHandler.
// The inheritance tree for SyncSessionHandler is:
//
// WebServiceHandler
// ----> SyncSessionlessHandler
// ----> SyncSessionHandler
//
// We need to walk the tree up to the WebServiceHandler class.
bool exitLoop = false;
Type t = originalHandler.GetType();
while (t != null)
{
// WebServiceHandler is internal, so again another string comparison.
if (t.ToString() == "System.Web.Services.Protocols.WebServiceHandler")
{
// WebServiceHandler has a private field named protocol. This field has the type HttpGetServerProtocol.
FieldInfo protocolField = t.GetField("protocol", BindingFlags.NonPublic | BindingFlags.Instance);
object protocolValue = protocolField.GetValue(originalHandler);
// The inheritance tree for ServerProtocol is:
//
// HttpServerProtocol
// ----> HttpGetServerProtocol
//
// We need to walk the three up to the HttpServerProtocol class.
Type t2 = protocolValue.GetType();
while (t2 != null)
{
if (t2.ToString() == "System.Web.Services.Protocols.HttpServerProtocol")
{
// HttpServerProtocol has an internal property named MethodInfo. This property has the type LogicalMethodInfo.
PropertyInfo methodInfoProperty = t2.GetProperty("MethodInfo", BindingFlags.NonPublic | BindingFlags.Instance);
object methodInfoValue = methodInfoProperty.GetValue(protocolValue);
// The LogicalMethodInfo class has a DeclaringType property. This property stores the type of the ASMX service.
att = Attribute.GetCustomAttribute(((LogicalMethodInfo)methodInfoValue).DeclaringType, typeof(ModuleAssignmentAttribute));
exitLoop = true;
break;
}
t2 = t2.BaseType;
}
}
if (exitLoop) break;
t = t.BaseType;
}
}
else
{
att = Attribute.GetCustomAttribute(HttpContext.Current.Handler.GetType(), typeof(ModuleAssignmentAttribute));
}
if (att != null)
{
Module[] modules = ((ModuleAssignmentAttribute)att).Modules;
// Simulate getting the user's active role ID
int roleId = 1;
// Simulate performing an authz check
AuthorizationAgent agent = new AuthorizationAgent();
bool authorized = agent.AuthorizeRequest(roleId, modules);
if (!authorized)
{
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.StatusCode = 401;
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
}
}
我必须使用Reflector+运行时调试来找到这个解决方案。HttpContext.Current.Handler.GetType()的值是多少?@Mason-System.Web.Script.Services.ScriptHandlerFactory+HandlerWrapperWithSession我想这是你的问题。处理程序不是你期望的
SomeService
类。它正在检索的类没有该属性。不幸的是,我不知道是否有可靠的方法从该上下文中获取ASMX类。你知道吗可能可以通过检查URL或路由来实现。如果可以的话,将所有ASMX转换为ASHX可能会更容易。@Mason-不幸的是,这不是一个可行的解决方案。有70多个服务/1000多个web方法。你有路由吗?或者是像~/SomeService.ASMX/GetValue
这样的简单URL吗?你可能可以使用URL来确定ich服务类实例化并从中获取属性。