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;。答案 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会正常工作。