ASP.NET中的UWP组件的ArgumentException,但不在控制台.NET中

时间:2016-12-14 21:41:09

标签: asp.net uwp

I'm trying to consume an UWP component in an ASP.NET page.最小代码:

public partial class _default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Try();
    }

    private void Try()
    {
        Debug.WriteLine("Before");
        Windows.Foundation.Collections.StringMap sm = new Windows.Foundation.Collections.StringMap();
        Debug.WriteLine("After");
    }
}

为了进行编译,您需要将以下行添加到项目文件中:

<TargetPlatformVersion>10.0</TargetPlatformVersion>

并在&#34; Universal Windows&#34;中添加对Windows.Foundation的引用。类别。黄色错误屏幕显示:

The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG)) 

它显示了Try()的最后一行作为错误位置,但这是误导性的;当框架尝试编译方法Try()时,在JIT编译器中抛出错误。与任何其他UWP课程相同的错误,我已经尝试了几个。

这在IIS Express和IIS下都失败了。 相同的代码在控制台.NET应用程序中按预期工作。

桌面/控制台和ASP.NET下的执行环境有什么不同?不是当前用户;在IIS Express方案中,当前用户是我。不是公寓的线程模型;我已经在STA线程和MTA线程上尝试过它。

编辑:它是a bug at VS Connect now。如果您受到影响,请点击&#34;我也可以&#34;。

1 个答案:

答案 0 :(得分:0)

该错误与ASP.NET的AppDomain程序集共享策略有关,该策略大致对应于AppDomainSetup的LoaderOptimization参数。如果UWP消费代码在AppDomain中执行,其中LoaderOptimization设置为SingleDomain(桌面应用程序的默认设置),则可以使用。 ASP.NET将此设置硬编码为MultiDomainHost。它在某种程度上可能是一个CLR错误。

我发现没有合法的方法可以更改ASP.NET沙盒应用程序的设置,但您可以创建一个新的应用程序域,除了LoaderOptimization之外,其所有参数都与沙箱相同:< / p>

AppDomain CreateUnsharingDomain()
{
    AppDomain cad = AppDomain.CurrentDomain;
    AppDomainSetup cads = cad.SetupInformation;
    return AppDomain.CreateDomain("Dummy", cad.Evidence,
        new AppDomainSetup
        {
            ApplicationName = cads.ApplicationName,
            ApplicationBase = cads.ApplicationBase,
            DynamicBase = cads.DynamicBase,
            CachePath = cads.CachePath,
            PrivateBinPath = cads.PrivateBinPath,
            ShadowCopyDirectories = cads.ShadowCopyDirectories,
            ShadowCopyFiles = cads.ShadowCopyFiles,
            ApplicationTrust = cads.ApplicationTrust,
            LoaderOptimization = LoaderOptimization.SingleDomain
        });
        //Not sure which other properties to copy...
}

CreateUnsharingDomain().DoCallBack(() =>
{
    Debug.WriteLine("Before");
    Windows.Foundation.Collections.StringMap sm = new Windows.Foundation.Collections.StringMap();
    Debug.WriteLine("After");
});

这很有效。我仍然不完全满意答案。它相当冗长,并且跨AppDomain边界传递调用和对象是一件苦差事。我正在调查你是否可以在配置文件中设置它。

编辑:可能不可能。 ASP.NET没有在其AppDomains上明确指定LoaderOptimization。相反,当查询域级别程序集共享策略时,框架将回退到基于{{1}的值在CLR进程启动时初始化的每进程共享策略。进程'主要功能'的属性。由于那个深入ASP.NET代码,因此无法改变全局策略。

理论上,共享可以基于每个程序集禁用,但对于WinRT,LoaderOptimization命名空间中的程序集都被认为是可共享的,没有任何钩子可以覆盖它。

说到非法更改AppDomain上的LoaderOptimization的方法,AppDomain类中有私有方法Windows.*。你可以通过反思来调用它,包含所有常见的警告:

SetupLoaderOptimization(LoaderOptimization policy)

这对我也有用。您决定哪种方法问题较少。后者的线条较少,前者不依赖于未记录的私人方法。

以下详细说明,请自行承担风险。

使用本机调试器调试IISExpress会显示在以下堆栈中抛出C ++异常:

AppDomain ad = AppDomain.CurrentDomain;
MethodInfo mi = ad.GetType().GetMethod("SetupLoaderOptimization", BindingFlags.Instance | BindingFlags.NonPublic);
mi.Invoke(ad, new object[] { LoaderOptimization.SingleDomain });

//And for the win:
Windows.Foundation.Collections.StringMap sm = new Windows.Foundation.Collections.StringMap();

因此将UWP库作为程序集加载到应用程序域时出现问题... AppDomain设置有何不同?我尝试过一个新创建的AppDomain,结果相同。

编辑:我确实启用了日志记录,消息相当不确定:

KernelBase.dll!_RaiseException@16() Unknown
msvcr120_clr0400.dll!__CxxThrowException@8()    Unknown
clr.dll!DomainFile::ExInfo::Throw(void) Unknown
clr.dll!DomainFile::EnsureLoadLevel(enum FileLoadLevel) Unknown
clr.dll!AppDomain::LoadDomainAssemblyInternal(class AssemblySpec *,class PEAssembly *,enum FileLoadLevel,struct AssemblyLoadSecurity *) Unknown
clr.dll!AppDomain::LoadDomainAssembly(class AssemblySpec *,class PEAssembly *,enum FileLoadLevel,struct AssemblyLoadSecurity *) Unknown
clr.dll!CLRPrivTypeCacheWinRT::ContainsType(struct ICLRPrivAssembly *,unsigned short const *)   Unknown
clr.dll!CLRPrivBinderWinRT::BindWinRTAssemblyByName(struct IAssemblyName *,class CLRPrivAssemblyWinRT * *,int)  Unknown
clr.dll!CLRPrivBinderWinRT::BindWinRTAssemblyByName(struct IAssemblyName *,struct ICLRPrivAssembly * *,int) Unknown
clr.dll!CLRPrivBinderWinRT::BindAssemblyByName(struct IAssemblyName *,struct ICLRPrivAssembly * *)  Unknown
clr.dll!AppDomain::BindAssemblySpecForHostedBinder(class AssemblySpec *,struct IAssemblyName *,struct ICLRPrivBinder *,class PEAssembly * *)    Unknown
clr.dll!AppDomain::BindAssemblySpec(class AssemblySpec *,int,int,enum StackCrawlMark *,struct AssemblyLoadSecurity *,int)   Unknown
clr.dll!PEFile::LoadAssembly(unsigned int,struct IMDInternalImport *,char const *,char const *) Unknown
clr.dll!Module::LoadAssembly(class AppDomain *,unsigned int,char const *,char const *)  Unknown
clr.dll!Assembly::FindModuleByTypeRef(class Module *,unsigned int,enum Loader::LoadFlag,int *)  Unknown
clr.dll!ClassLoader::LoadTypeDefOrRefThrowing(class Module *,unsigned int,enum ClassLoader::NotFoundAction,enum ClassLoader::PermitUninstantiatedFlag,unsigned int,enum ClassLoadLevel) Unknown
clr.dll!MemberLoader::GetDescFromMemberRef(class Module *,unsigned int,class MethodDesc * *,class FieldDesc * *,class SigTypeContext const *,int,class TypeHandle *,int,unsigned char const * *,unsigned long *)    Unknown
clr.dll!CEEInfo::resolveToken(struct CORINFO_RESOLVED_TOKEN *)  Unknown
clrjit.dll!Compiler::impResolveToken(unsigned char const *,struct CORINFO_RESOLVED_TOKEN *,enum CorInfoTokenKind)   Unknown
clrjit.dll!Compiler::impImportBlockCode(struct BasicBlock *)    Unknown
clrjit.dll!Compiler::impImportBlock(struct BasicBlock *)    Unknown
clrjit.dll!Compiler::impImport(struct BasicBlock *) Unknown
clrjit.dll!Compiler::compCompile(void * *,unsigned long *,unsigned int) Unknown

可能相关:Why am I unable to do an Assembly.Load of WinMD files?

EDIT2:上面的调用堆栈是第二次尝试使用UWP类。第一次尝试显示不同的调用堆栈;它可能是CLR缓存“无法加载”状态并重用它。这是:

The operation was successful.
Bind result: hr = 0x1. Incorrect function.

Assembly manager loaded from:      C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable  C:\Program Files (x86)\IIS Express\iisexpress.exe
--- A detailed error log follows. 

BEGIN : Native image bind.
END   : Incorrect function. (Exception from HRESULT: 0x00000001 (S_FALSE))

APTCA代表“AllowPartiallyTrustedCallersAttribute”。但是,在完全信任下运行(通过KernelBase.dll!_RaiseException@16() Unknown msvcr120_clr0400.dll!__CxxThrowException@8() Unknown clr.dll!ThrowHR(long) Unknown clr.dll!DomainCanShareAptcaAssembly(class DomainAssembly *) Unknown clr.dll!DomainAssembly::ShouldLoadDomainNeutralHelper(void) Unknown clr.dll!DomainAssembly::ShouldLoadDomainNeutral(void) Unknown clr.dll!DomainAssembly::Allocate(void) Unknown clr.dll!DomainFile::DoIncrementalLoad(enum FileLoadLevel) Unknown clr.dll!AppDomain::TryIncrementalLoad(class DomainFile *,enum FileLoadLevel,class Wrapper<class FileLoadLock *,&DoNothing<class FileLoadLock *>(class FileLoadLock *),&FileLoadLock::HolderLeave(class FileLoadLock *),0,&CompareDefault<class FileLoadLock *>(class FileLoadLock *,class FileLoadLock *),2,1> &) Unknown clr.dll!AppDomain::LoadDomainFile(class FileLoadLock *,enum FileLoadLevel) Unknown clr.dll!AppDomain::LoadDomainAssemblyInternal(class AssemblySpec *,class PEAssembly *,enum FileLoadLevel,struct AssemblyLoadSecurity *) Unknown clr.dll!AppDomain::LoadDomainAssembly(class AssemblySpec *,class PEAssembly *,enum FileLoadLevel,struct AssemblyLoadSecurity *) Unknown clr.dll!CLRPrivTypeCacheWinRT::ContainsType(struct ICLRPrivAssembly *,unsigned short const *) Unknown clr.dll!CLRPrivBinderWinRT::BindWinRTAssemblyByName(struct IAssemblyName *,class CLRPrivAssemblyWinRT * *,int) Unknown clr.dll!CLRPrivBinderWinRT::BindWinRTAssemblyByName(struct IAssemblyName *,struct ICLRPrivAssembly * *,int) Unknown clr.dll!CLRPrivBinderWinRT::BindAssemblyByName(struct IAssemblyName *,struct ICLRPrivAssembly * *) Unknown clr.dll!AppDomain::BindAssemblySpecForHostedBinder(class AssemblySpec *,struct IAssemblyName *,struct ICLRPrivBinder *,class PEAssembly * *) Unknown clr.dll!AppDomain::BindAssemblySpec(class AssemblySpec *,int,int,enum StackCrawlMark *,struct AssemblyLoadSecurity *,int) Unknown clr.dll!PEFile::LoadAssembly(unsigned int,struct IMDInternalImport *,char const *,char const *) Unknown clr.dll!Module::LoadAssembly(class AppDomain *,unsigned int,char const *,char const *) Unknown clr.dll!Assembly::FindModuleByTypeRef(class Module *,unsigned int,enum Loader::LoadFlag,int *) Unknown clr.dll!ClassLoader::LoadTypeDefOrRefThrowing(class Module *,unsigned int,enum ClassLoader::NotFoundAction,enum ClassLoader::PermitUninstantiatedFlag,unsigned int,enum ClassLoadLevel) Unknown clr.dll!MemberLoader::GetDescFromMemberRef(class Module *,unsigned int,class MethodDesc * *,class FieldDesc * *,class SigTypeContext const *,int,class TypeHandle *,int,unsigned char const * *,unsigned long *) Unknown clr.dll!CEEInfo::resolveToken(struct CORINFO_RESOLVED_TOKEN *) Unknown clrjit.dll!Compiler::impResolveToken(unsigned char const *,struct CORINFO_RESOLVED_TOKEN *,enum CorInfoTokenKind) Unknown clrjit.dll!Compiler::impImportBlockCode(struct BasicBlock *) Unknown clrjit.dll!Compiler::impImportBlock(struct BasicBlock *) Unknown clrjit.dll!Compiler::impImport(struct BasicBlock *) Unknown clrjit.dll!Compiler::compCompile(void * *,unsigned long *,unsigned int) Unknown )根本没有帮助。

在异常时,本机调试器中的“模块”窗口将Windows.Foundation.winmd显示为已加载。所以它不是以某种方式找不到文件的工件。

编辑:这绝对与以下事实有关:在ASP.NET下,代码在沙盒AppDomain中以部分受信任的方式运行。在非沙箱AppDomain中,甚至不会调用此逻辑。该错误不是安全违规,或者消息可能不同。

编辑:将其追踪到源位置。在aptca.cpp中,在system.web/fullTrustAssemblies中,有一行:

DomainCanShareAptcaAssembly()

失败并抛出,因为 IfFailThrow(pDomainAssembly->GetAppDomain()->GetFusionContext()->GetAssemblyBindingClosure(pFusionAssembly, pNIPath, &pClosure)); 参数为null。参数为null,因为局部变量pFusionAssembly为null。局部变量在行

中初始化
pFusionAssembly

为null,因为pFusionAssembly = pDomainAssembly->GetFile()->GetIHostAssembly(); 对象是在pDomainAssembly(在appdomain.cpp中)通过带有5个args的AppDomain::BindHostedPrivAssembly()调用创建的,它传递了一个硬编码的{{在PEAssembly:Open()参数中的1}}。这可能是CLR中的一个微妙的错误,但完全有可能解决方法 - 可以缩短对nullptr的调用。

仅当程序集加载逻辑尝试在应用程序域之间共享程序集时,才会导致导致pHostAssembly的代码路径。在ASP.NET中,就是这种情况。代码路径的不同之处在于调用DomainCanShareAptcaAssembly()的{​​{1}}函数;在ASP.NET环境中,后者返回3(DomainCanShareAptcaAssembly()),而在控制台项目中它返回1(AppDomain::ApplySharePolicyFlag())。共享策略由GetSharePolicy()的{​​{1}}参数驱动。只要域名在SHARE_POLICY_GAC运行,共享逻辑就会缩短,UWP会正常工作。