質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Xamarin

Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

Q&A

解決済

1回答

2820閲覧

Xamarin C# で Directory.Existsの戻り値が変わってしまいます

as00000

総合スコア21

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Xamarin

Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

0グッド

0クリップ

投稿2020/03/31 07:44

編集2020/04/03 00:49

前提・実現したいこと

VisualStudio2019 Xamarin で Directory.Exists を使用して
フォルダの存在確認をしているのですが
間違いなく存在しているフォルダのチェックを行なっても
ViewModelからアクセスすると"False"が返って来てしまいます
(Testコードからアクセスすると"True"となるのに)

何故、この様な挙動になるのか
同じ結果が返る様にするには、どこを直せば良いのかが全く分かりません

ご教示をお願いします


※4/1追記

C#

1DirectoryInfo directoryInfo = new DirectoryInfo(targetFolderPath); 2 3 if (Directory.Exists(targetFolderPath)) 4                  ~

Directory.Existsの前でDirectoryInfoを確認してみた所
イメージ説明
'System.UnauthorizedAccessException' の例外が出ていました
(フォルダ名は事情により少し変えていますが、フォルダは間違いなく存在します)

Windowsは管理者権限で立ち上げていますし、VisualStudioを管理者権限で起動しても
結果は変わりませんでした

このエラーのせいでFalseが返って来ているのだと思いますが
エラーの原因が分かりません


※4/3追記

f-miyuさんに依頼頂いたので
変更後の Package.appxmanifest と UWP側で書いたコードを追記します

xml

1<?xml version="1.0" encoding="utf-8"?> 2 3<!--<Package 4 xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" 5 xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" 6 xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" 7 IgnorableNamespaces="uap mp">--> 8 9<Package 10xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" 11xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" 12xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" 13xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" 14IgnorableNamespaces="uap mp rescap"> 15 16... 17 18 <!--<Capabilities> 19 <Capability Name="internetClient" /> 20 </Capabilities>--> 21 22 <Capabilities> 23 <rescap:Capability Name="broadFileSystemAccess" /> 24 </Capabilities> 25 26</Package>

↓とりあえず動作確認の為に、項目の少ないインターフェースを作成しました

C#

1 2[assembly: Dependency(typeof(DataOperatorUWP))] 3namespace PlaceTheProcessingData.UWP 4{ 5 class DataOperatorUWP : IDataOperator 6 { 7 public async Task<TargetFiles> GetAllSourceDataAsync(DirectoryPath sourcePath) 8 { 9 // 『sourcePath.Main = public List<string> GetSourceFiles(string targetFolderPath)に 10 // 渡していた targetFolderPathです』 11 var folder = await StorageFolder.GetFolderFromPathAsync(sourcePath.Main); //←【ここから進みません】 12 var files = await folder.GetFilesAsync(); 13 14 return new TargetFiles(); 15 16 } 17 18 public TargetFiles GetSpecificedCodeData(string projectCode, DirectoryPath sourcePath) 19 { 20 throw new NotImplementedException(); 21 } 22 } 23} 24

↓インターフェースの定義

C#

1 public interface IDataOperator 2 { 3 4 Task<TargetFiles> GetAllSourceDataAsync(DirectoryPath sourcePath); 5 TargetFiles GetSpecificedCodeData(string projectCode, DirectoryPath sourcePath); 6 7 }

↓実際にUWP側を呼び出している部分

C#

1 public void GetFileInfo() 2 { 3 4 var dataOperator = DependencyService.Get<IDataOperator>(); 5 this.SourceAllData = dataOperator.GetAllSourceDataAsync(this.SourcePath).Result; 6 7 this.SourceAllData = this.dataOperator.GetAllSourceData(this.SourcePath); 8 this.SourceSpecificedCodeData = this.dataOperator.GetSpecificedCodeData(this.Code, this.SourcePath); 9 this.DestinationSpecificedCodeData = this.dataOperator.GetSpecificedCodeData(this.Code, this.DestinationPath); 10 this.SaveSpecificedCodeData = this.dataOperator.GetSpecificedCodeSaveFolders(this.Code, this.SavePath); 11

該当のソースコード

Testからメソッドを呼び出している部分(希望通りTrueになるパターン)

C#

1[TestMethod()] 2 public void GetFileInfoTest() 3 { 4 Project project = new Project(new DataOperator()); 5 6 project.Code = "10025"; 7 project.GetFileInfo(); 8 9以下 略

ViewModelからメソッドを呼び出している部分(Falseになってしまうパターン)

C#

1public class ProjectViewModel : BindableBase, IDisposable 2 { 3 private CompositeDisposable Disposable { get; } = new CompositeDisposable(); 4 public Project ProjectModel { get; } 5 6 7 [CodeValidation] 8 public ReactiveProperty<string> Code { get; set; } = new ReactiveProperty<string>(); 9 public ReactiveProperty<string> Name { get; set; } = new ReactiveProperty<string>(); 10 public ReactiveProperty<string> CodeAndName { get; set; } = new ReactiveProperty<string>(); 11 12 public ReactiveProperty<string> SourceStatusInfo_Main { get; set; } = new ReactiveProperty<string>(); 13 14 public ReactiveCommand ClearInputCommand { get; private set; } = new ReactiveCommand(); 15 public ReactiveCommand RefreshInfoCommand { get; private set; } = new ReactiveCommand(); 16 17 18 public ProjectViewModel(Project projectModel) 19 { 20 this.ProjectModel = projectModel; 21 22 23 this.Code = projectModel.ToReactivePropertyAsSynchronized(x => x.Code).SetValidateAttribute(() => Code); 24 this.Name = projectModel.ToReactivePropertyAsSynchronized(x => x.Name); 25 this.CodeAndName = projectModel.ToReactivePropertyAsSynchronized(x => x.CodeAndName); 26 27 28 ClearInputCommand.Subscribe(_ => projectModel.ClearInput()); 29 30 RefreshInfoCommand = Code.ObserveHasErrors.Select(x => !x).ToReactiveCommand(); 31 RefreshInfoCommand.Subscribe(_ => projectModel.GetFileInfo()); ←【ここで設定してます】 32 33 } 34 35 public void Dispose() => this.Disposable.Dispose(); 36 37 }

ViewModel・Testから呼び出しているメソッド

C#

1public void GetFileInfo() 2 { 3 this.SourceAllData = this.dataOperator.GetAllSourceData(this.SourcePath); 4 this.SourceSpecificedCodeData = this.dataOperator.GetSpecificedCodeData(this.Code, this.SourcePath); 5 this.DestinationSpecificedCodeData = this.dataOperator.GetSpecificedCodeData(this.Code, this.DestinationPath); 6 this.SaveSpecificedCodeData = this.dataOperator.GetSpecificedCodeSaveFolders(this.Code, this.SavePath); 7 8以下 略 9

GetAllSourceDataに渡している引数(Pathのstringをまとめただけのクラスです)

C#

1public DirectoryPath SourcePath 2 { 3 get 4 { 5 return new DirectoryPath() 6 { 7 Main = "C:\Users\as\Desktop\データ\Mainデータ出力", 8 Sub = "C:\Users\as\Desktop\データ\Subデータ出力" 9 }; 10 11 } 12 } 13

上記 dataOperator.GetAllSourceData のコード

C#

1public TargetFiles GetAllSourceData(DirectoryPath sourcePath) 2 3 { 4 5 TargetFiles getAllSourceData = new TargetFiles() 6 { 7 Main = this.fo.GetSourceFiles(sourcePath.Main), 8 Sub = this.fo.GetSourceFiles(sourcePath.Sub) 9 }; 10

更に呼び出されている fo.GetSourceFiles(Directory.Existsを使用している部分)

C#

1public List<string> GetSourceFiles(string targetFolderPath) 2 { 3 4 if (Directory.Exists(targetFolderPath)) ←【ここの返り値が変わってしまう】 5 { 6 List<string> getSourceFiles = new List<string>(); 7 getSourceFiles.AddRange(Directory.GetFiles(targetFolderPath)); 8 9 return getSourceFiles; 10 11 } 12 else 13 { 14 return null; 15 } 16 } 17

試したこと

SourcePathのパス文字がおかしいのかと
Main = "C:\Users\as\Desktop\データ\Mainデータ出力"

Main = "C:\Users\as\Desktop\データ\Mainデータ出力"
に変更

ProjectViewModel 内で
RefreshInfoCommand.Subscribe(_ => projectModel.GetFileInfo());

RefreshInfoCommand.Subscribe(_ => ProjectModel.GetFileInfo());
に変更
(参照が違ってしまっているのかと、引数からプロパティに変更してみた)

しましたが、変わりませんでした

補足情報(FW/ツールのバージョンなど)

Microsoft Visual Studio Community 2019
Version 16.4.5
VisualStudio.16.Release/16.4.5+29806.167
Microsoft .NET Framework
Version 4.8.03752

インストールされているバージョン:Community

Visual C++ 2019 00435-60000-00000-AA788
Microsoft Visual C++ 2019

ASP.NET and Web Tools 2019 16.4.460.23317

ASP.NET Web Frameworks and Tools 2019 16.4.460.23317

Azure App Service Tools v3.0.0 16.4.460.23317

Azure Functions and Web Jobs Tools 16.4.460.23317

C# ツール 3.4.1-beta4-19614-01+165046097562cfe65b09c2e9a9d8f7cd88526f2c

Common Azure Tools 1.10

Extensibility Message Bus 1.2.0 (d16-2@8b56e20)

F# 4.6 用 Visual F# Tools 10.4 16.4.0-beta.19556.5+e7597deb7042710a7142bdccabd6f92b0840d354

Microsoft Azure Tools 2.9

Microsoft Continuous Delivery Tools for Visual Studio 0.4

Microsoft JVM Debugger 1.0

Microsoft MI-Based Debugger 1.0

Microsoft Visual C++ ウィザード 1.0

Microsoft Visual Studio Tools for Containers 1.1

Microsoft Visual Studio VC パッケージ 1.0

Mono Debugging for Visual Studio 16.5.24 (1fafd7e)

NuGet パッケージ マネージャー 5.4.0

PHP Tools for Visual Studio 1.32.11706.2019

ProjectServicesPackage Extension 1.0

SQL Server Data Tools 16.0.62002.03150

StylerPackage Extension 1.0

TypeScript Tools 16.0.11031.2001

Visual Basic ツール 3.4.1-beta4-19614-01+165046097562cfe65b09c2e9a9d8f7cd88526f2c

Visual Studio Code デバッグ アダプターのホスト パッケージ 1.0

Visual Studio Tools for Containers 1.0

Visual Studio コンテナー ツール拡張機能 (プレビュー) 1.0

VisualStudio.DeviceLog 1.0

VisualStudio.Foo 1.0

VisualStudio.Mac 1.0

Xamarin 16.4.000.311 (d16-4@ddfd842)

Xamarin Designer 16.4.0.475 (remotes/origin/d16-4@ac250f5aa)

Xamarin Templates 16.4.25 (579ee62)

Xamarin.Android SDK 10.1.4.0 (d16-4/e44d1ae)
Xamarin.Android Reference Assemblies and MSBuild support.
Mono: fd9f379
Java.Interop: xamarin/java.interop/d16-4@c4e569f
ProGuard: xamarin/proguard/master@905836d
SQLite: xamarin/sqlite/3.28.0@46204c4
Xamarin.Android Tools: xamarin/xamarin-android-tools/d16-5@9f4ed4b

Xamarin.iOS and Xamarin.Mac SDK 13.10.0.17 (5f802ef)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

UWPアプリは、アクセスできるファイルに制限があります。全ファイルのアクセス権限を付与するには、Package.appxmanifestを以下のように更新し、ビルドした後に、設定画面の[プライバシー] > [ファイル システム]から対象のアプリの許可をオンにしてください。

xml

1<Package 2 ... 3 xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" 4 IgnorableNamespaces="uap mp uap5 rescap"> 5... 6<Capabilities> 7 <rescap:Capability Name="broadFileSystemAccess" /> 8</Capabilities>

参照:ファイル アクセス許可

ただおそらくそれでも、Directory.Existsだとfalseを返すのではないかと思うので、UWPプロジェクトの方で、Windows.Storage.StorageFolderを用いてファイル操作をした方がいいかもしれません。

c#

1try 2{ 3 var folder = await StorageFolder.GetFolderFromPathAsync(targetFolderPath); 4 var files = await folder.GetFilesAsync(); 5} 6catch 7{ 8}

dataOperator.GetAllSourceDataAsync(this.SourcePath).Resultは、現在のスレッドをブロックするので、await StorageFolder.GetFolderFromPathAsync(sourcePath.Main)の完了後に元のスレッドに戻ることができなくて、デッドロックが発生してしまいます。ConfigureAwait(false)で元のスレッドに戻らないようにするか、そもそもResultではなく、awaitを使うようにするかのどちらかの対応を行う必要があります。

C#

1 public async Task<TargetFiles> GetAllSourceDataAsync(DirectoryPath sourcePath) 2 { 3 var folder = await StorageFolder.GetFolderFromPathAsync(sourcePath.Main).AsTask().ConfigureAwait(false); 4 var files = await folder.GetFilesAsync().AsTask().ConfigureAwait(false); 5 6 return new TargetFiles(); 7 8 }

C#

1 public async Task GetFileInfo() 2 { 3 4 var dataOperator = DependencyService.Get<IDataOperator>(); 5 this.SourceAllData = await dataOperator.GetAllSourceDataAsync(this.SourcePath);

投稿2020/04/01 19:21

編集2020/04/03 16:00
f-miyu

総合スコア1625

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

as00000

2020/04/02 07:21

ご回答ありがとうございます アドバイス頂いた通り Package.appxmanifest を書き換えてみましたが xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" の箇所に対して ------------------------------------------------------------------------------------------------- 要素 名前空間 'http://schemas.microsoft.com/appx/manifest/foundation/windows10' の 'Capabilities' には 無効な子要素 名前空間 'http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities' の 'Capability' が含まれています。 必要とされる要素は 名前空間 'http://schemas.microsoft.com/appx/manifest/foundation/windows10' の 'CapabilityChoice' および 名前空間 'http://schemas.microsoft.com/appx/manifest/uap/windows10' の 'Capability' および 名前空間 'http://schemas.microsoft.com/appx/manifest/foundation/windows10' の 'Capability' および 名前空間 'http://schemas.microsoft.com/appx/manifest/uap/windows10/4' の 'Capability' および 名前空間 'http://schemas.microsoft.com/appx/manifest/uap/windows10/6' の 'Capability' および 名前空間 'http://schemas.microsoft.com/appx/manifest/uap/windows10/7' の 'Capability' および 名前空間 'http://schemas.microsoft.com/appx/manifest/uap/windows10/3' の 'Capability' および 名前空間 'http://schemas.microsoft.com/appx/manifest/uap/windows10/2' の 'Capability' および 名前空間 'http://schemas.microsoft.com/appx/manifest/foundation/windows10' の 'CustomCapabilityChoice' および 名前空間 'http://schemas.microsoft.com/appx/manifest/uap/windows10/4' の 'CustomCapability' および 名前空間 'http://schemas.microsoft.com/appx/manifest/foundation/windows10' の 'DeviceCapability' です。 ------------------------------------------------------------------------------------------------- と警告が出てしまいます。 一応ビルド→起動は出来るのでデバッグしてみましたが、UWP側の var folder = await StorageFolder.GetFolderFromPathAsync(targetFolderPath); の所で処理が進まなくなってしまいます。 素人なりの推測ですが 警告で提示されている何れかの参照に変更すれば良いのだとは思うのですが 適当に選んで動けば良いのではない様な気がするので どの様に対処すれば良いか、アドバイス頂ければ幸いです (回答への質問になってしまい申し訳ありません)
f-miyu

2020/04/02 14:58

警告は特に問題はないです。例外が出るならまだしも、進まなくなるというのは何か別の問題がありそうです。Package.appxmanifestと書いたコードをあげてもらってもよろしいでしょうか?
as00000

2020/04/03 00:50

ご回答ありがとうございます。 本文の方に変更後のコードを追記しましたので、確認をお願いします
f-miyu

2020/04/03 16:00

回答の方に追記しました
as00000

2020/04/04 03:19

ご回答ありがとうございます 休日に入ってしまいましたので、週明けにご指摘の箇所を修正してみて 結果をご報告いたします。 取り急ぎ、ご連絡まで・・・
as00000

2020/04/06 06:17

回答ありがとうございました。 何もかも不慣れで、確認に時間が掛かってしまいましたが ご提示頂いた「Resultではなく、awaitを使うように」する方法で 無事フォルダにアクセス出来ました。 有無の確認は"FileNotFoundException"の発生有無で確認する様に 組み立てて行こうと思います。 又"Task"や"await,async"の非同期処理(?)もコピペで動いている感じなので 徐々に学習して行きたいと思います。 長々とお付き合い頂き、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問