简体   繁体   English

从 System.IO.Abstractions 抛出 UnauthorizedAccessException

[英]Throw UnauthorizedAccessException from System.IO.Abstractions

I'm using System.IO.Abstractions ( https://github.com/System-IO-Abstractions ) to allow me to inject an IFileSystem into my class.我正在使用System.IO.Abstractions ( https://github.com/System-IO-Abstractions ) 来允许我将IFileSystem注入我的班级。 I've recently added a piece of code to catch an UnauthorizedAccessException thrown when the user tries to create a file in a directory which they don't have write access to.我最近添加了一段代码来捕获当用户尝试在他们没有写访问权限的目录中创建文件时抛出的UnauthorizedAccessException

Is there a way the set the access permissions of a directory within System.IO.Abstractions ?有没有办法在System.IO.Abstractions设置目录的访问权限?

The following code is as close as I have come ( MockFileSystem coming from System.IO.Abstractions ).下面的代码和我一样接近( MockFileSystem来自System.IO.Abstractions )。 The AccessControlSections description is AccessControlSections描述是

Specifies which sections of a security descriptor to save or load指定要保存或加载的安全描述符的哪些部分

So it appears that I need to set up a security descriptor of some sort but I can't find any information on that - or if this is even the right approach.所以看起来我需要设置某种安全描述符,但我找不到任何关于它的信息 - 或者这是否是正确的方法。

var mockFileSystem = new MockFileSystem();
mockFileSystem.Directory.CreateDirectory("C:\\Test", new DirectorySecurity("C:\\Test", AccessControlSections.None));

// This should throw an UnauthorizedAccessException
mockFileSystem.File.Create("C:\\Test\\File.txt");

I tried something like this and failed: 我尝试了类似的操作,但失败了:

const string path = @"C:\temp\incoming";
var fileSystem = new MockFileSystem();
fileSystem.AddDirectory(path);
var diFactory = fileSystem.DirectoryInfo;
var directoryInfo = diFactory.FromDirectoryName(path);
var directorySecurity = directoryInfo.GetAccessControl();
var currentUser = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
directorySecurity.AddAccessRule(new FileSystemAccessRule(currentUser , FileSystemRights.Read, AccessControlType.Allow));

I still think this is more or less the way to go, unfortunately it doesn't work :-( 我仍然认为这或多或少是要走的路,不幸的是它不起作用:-(

Maybe the user I'm specifying for the AccessRule isn't correct, I've tried with others too but to no avail: 也许我为AccessRule指定的用户不正确,我也尝试了其他用户,但无济于事:

var adminUser = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
// -> Doesn't work either..

Anyway, in the end I created this dirty workaround to test it, and that works obviously: 无论如何,最后我创建了这个肮脏的解决方法来对其进行测试,并且显然可以正常工作:

var mockFileSystem = new Mock<IFileSystem>();
mockFileSystem.Setup(x => x.File.Create(It.IsAny<string>())).Throws(new Exception());

You can create a mock for IFileSystem to setup the method you wanna throw the exception and then you create a MockFileSystem to be used only when necessary.您可以为IFileSystem创建一个模拟来设置您想要抛出异常的方法,然后您创建一个MockFileSystem仅在必要时使用。 You can setup your mock to return the "real" file system when only some methods are invoked.您可以设置模拟以在仅调用某些方法时返回“真实”文件系统。 In my case bellow, I wanted to only use MockFileSystem when using the Path .在我的情况下,我只想在使用Path时使用MockFileSystem

You will have to setup your test like this (please read the comments):您必须像这样设置测试(请阅读评论):

[Fact]
public async void FailWhenCopyFails()
{
   // Arrange
   var file = Substitute.For<IFile>(); // fake File to throw UnauthorizedAccessException
   file
      .When(x => x.WriteAllBytesAsync(Arg.Any<string>(), Arg.Any<byte[]>()))
      .Do(x => { throw new UnauthorizedAccessException(); });

   file.Exists("C:\\Downloads\\" + "eclipse.exe").Returns(true);

   var fileSystem = Substitute.For<IFileSystem>(); // fake file system
   var mockFileSystem = new MockFileSystem(); // "real" file system to be used only when necessary
   fileSystem.File.Returns(file); // pass the File mock which will throw the exception
   fileSystem.Path.Returns(mockFileSystem.Path); // the "real" Path is necessary to make the test pass

   var httpResponseMessage = new HttpResponseMessage() { StatusCode = HttpStatusCode.OK };
   var httpClient = new HttpClient(new MockHttpMessageHandler(httpResponseMessage));
   var downloader = new DownloadManager(httpClient, fileSystem);

   // Act
   await Assert.ThrowsAsync<UnauthorizedAccessException>(() => downloader.DownloadFile(new Uri(eclipseUrl), downloadFolder));

   // Assert
   downloader.IsSuccess().Should().BeFalse();
}

In my case I wanted to verify the download fails if the http client can't create the downloaded file in the downloads folder (it was supposed to fail if it cannot overwrite the C:\\Downloads\\eclipse.exe already there).在我的情况下,我想验证下载是否失败,如果 http 客户端无法在下载文件夹中创建下载的文件(如果它不能覆盖已经存在的 C:\\Downloads\\eclipse.exe,它应该会失败)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM