Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for auto loading UNC paths #794

Merged
merged 1 commit into from
Jul 17, 2015

Conversation

mikeobrien
Copy link
Contributor

Re. #793, the GetNLogAssemblyLocation method does not support UNC paths. This can simply be replaced with Uri.LocalPath which does.

…th Uri.LocalPath in order to support UNC paths.
@304NotModified
Copy link
Member

Hi,

thanks for this PR. But I have to check this, AFAIK the LocalPath gave issues with ASP.Net (it would return the cached files path), so we can't use it. See mikeobrien@9032367

@304NotModified
Copy link
Member

Is the issue not resolved by removing Uri.UnescapeDataString?

@mikeobrien
Copy link
Contributor Author

Unless I'm totally missing something, I'm not seeing how Uri.LocalPath could return any other path than the one passed into the Uri constructor. Accoring to the docs:

Gets a local operating-system representation of a file name.

The value returned by this property is unescaped. If the path is recognized as a Windows file path, all forward slashes (/) are replaced by backward slashes ().

For the URI file://computer/file.ext, the absolute path is /file.ext and the local path is \computer\file.ext.

In both implementations the path passed in is nlogAssembly.CodeBase, that does not change. Uri.LocalPath simply parses that path, as GetNLogAssemblyLocation is attempting to do, it doesn't change the path. I think you might be thinking about Assembly.CodeBase vs Assembly.Location as discussed here. But this is not changing that part.

Uri.UnescapeDataString fails to properly parse UNC paths. nlogAssembly.CodeBase returns the UNC path of the share on which the assembly resides e.g. file://psf/Data/.... The Uri.UnescapeDataString call returns the absolute path /Data/.... This path translates to C:\Data\... for example, if used by code on c: (Which is what happens under IIS). This call to Directory.GetFiles then fails because of an invalid path.

A quick test (passing in the path directly instead of the assembly):

GetNLogAssemblyLocation("file://c:/folder/")
    .ShouldEqual(@"c:\folder");          <-- Succeeds

GetNLogAssemblyLocation("file://server/share/")
    .ShouldEqual(@"\\server\share");     <-- Fails: Returns \share

Uri.LocalPath on the other hand does parse it properly:

new Uri("file://c:/folder/").LocalPath
    .ShouldEqual(@"c:\folder\");

new Uri("file://server/share/").LocalPath
    .ShouldEqual(@"\\server\share\");

I did a manual test under IIS where the site was under a UNC path to verify and it worked a treat.

@304NotModified
Copy link
Member

I think you might be thinking about Assembly.CodeBase vs Assembly.Location as discussed here. But this is not changing that part.

Yes you are right. I had to check this (difficult on mobile) - and I looks good. So this is a good change 👍

@304NotModified 304NotModified added the bug Bug report / Bug fix label Jul 12, 2015
@304NotModified 304NotModified added this to the 4.1 milestone Jul 12, 2015
@304NotModified 304NotModified self-assigned this Jul 12, 2015
@304NotModified
Copy link
Member

Fixes #29. Fixes #793

304NotModified added a commit that referenced this pull request Jul 17, 2015
@304NotModified 304NotModified merged commit b45ead5 into NLog:master Jul 17, 2015
@jopbrown
Copy link

It's work fine on win7 now, but I still got exception on my winxp.

On line 275
With extensionDll = "\UNC_PATH\NLog.Windows.Forms.dll"

var extensionAssembly = Assembly.LoadFrom(extensionDll);

got exception

Could not load file or assembly "file://\UNC_PATH\NLog.Windows.Forms.dll"

It's seem Assembly.LoadFrom will add "file://" on winxp.

@304NotModified
Copy link
Member

Winxp....

@jopbrown
Copy link

I found the solution.
replace

var extensionAssembly = Assembly.LoadFrom(extensionDll);

with

var extensionAssembly = Assembly.Load(File.ReadAllBytes(extensionDll));

There may be not because of winxp, but security permission settings of SMB/CIFS.
Resolve this by Assembly.Load(bytes) instead of Assembly.LoadFrom(path) to bypass the restriction.

https://social.msdn.microsoft.com/Forums/vstudio/en-US/1ea1af93-16d4-423f-8341-59397a070618/operation-is-not-supported-err-in-assemblyloadfrom-using-unc-path?forum=netfxbcl

@304NotModified
Copy link
Member

But did you get a securityException before?
Please post the full stacktrace

@jopbrown
Copy link

Actually I didn't get securityException.
I try on another winxp(xp mode in win7) and get the same exception.
Well, maybe it really is just a bug on winxp.
Currently, I use Assembly.Load(bytes) work OK.

StackTrace:
       at xpTest.Program.Main(String[] args)
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.TypeInitializationException
       Message=The type initializer for 'NLog.Config.ConfigurationItemFactory' threw an exception.
       Source=NLog
       TypeName=NLog.Config.ConfigurationItemFactory
       StackTrace:
            at NLog.Config.ConfigurationItemFactory.get_Default()
            at NLog.Config.XmlLoggingConfiguration..ctor(String fileName) in \\uncxp\NLog-master\src\NLog\Config\XmlLoggingConfiguration.cs:line 66
            at NLog.LogFactory.LoadLoggingConfiguration(String configFile) in \\uncxp\NLog-master\src\NLog\LogFactory.cs:line 889
            at NLog.LogFactory.get_Configuration() in \\uncxp\NLog-master\src\NLog\LogFactory.cs:line 167
            at NLog.LogFactory.GetLogger(LoggerCacheKey cacheKey) in \\uncxp\NLog-master\src\NLog\LogFactory.cs:line 843
            at NLog.LogFactory.GetLogger(String name) in \\uncxp\NLog-master\src\NLog\LogFactory.cs:line 359
            at NLog.LogManager.GetLogger(String name) in \\uncxp\NLog-master\src\NLog\LogManager.cs:line 225
            at xpTest.Program..cctor() in \\uncxp\NLog-master\src\xpTest\Program.cs:line 12
       InnerException: System.IO.FileLoadException
            Message=Could not load file or assembly 'file://\\uncxp\NLog-master\src\xpTest\bin\Debug\NLog.Windows.Forms.dll' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)
            Source=mscorlib
            FileName=file://\\uncxp\NLog-master\src\xpTest\bin\Debug\NLog.Windows.Forms.dll
            FusionLog=""
            StackTrace:
                 at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
                 at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
                 at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection, Boolean suppressSecurityChecks)
                 at System.Reflection.RuntimeAssembly.InternalLoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, Boolean forIntrospection, Boolean suppressSecurityChecks, StackCrawlMark& stackMark)
                 at System.Reflection.Assembly.LoadFrom(String assemblyFile)
                 at NLog.Config.ConfigurationItemFactory.BuildDefaultFactory() in \\uncxp\NLog-master\src\NLog\Config\ConfigurationItemFactory.cs:line 260
                 at NLog.Config.ConfigurationItemFactory..cctor() in \\uncxp\NLog-master\src\NLog\Config\ConfigurationItemFactory.cs:line 70
            InnerException: System.NotSupportedException
                 Message=An attempt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework. This release of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable the loadFromRemoteSources switch. See http://go.microsoft.com/fwlink/?LinkId=155569 for more information.
                 InnerException: 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Bug report / Bug fix must have
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants