diff --git a/.gitignore b/.gitignore
index df6decd..d2fc613 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,6 +65,8 @@ local.properties
## TODO: If you have NuGet Package Restore enabled, uncomment this
packages/
+# output folder for building NuGet packages
+packaging/
# Visual C++ cache files
ipch/
diff --git a/.idea/.idea.Rothko/.idea/.gitignore b/.idea/.idea.Rothko/.idea/.gitignore
new file mode 100644
index 0000000..a91f7ad
--- /dev/null
+++ b/.idea/.idea.Rothko/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/.idea.Rothko.iml
+/projectSettingsUpdater.xml
+/modules.xml
+/contentModel.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/.idea.Rothko/.idea/.name b/.idea/.idea.Rothko/.idea/.name
new file mode 100644
index 0000000..5319a9f
--- /dev/null
+++ b/.idea/.idea.Rothko/.idea/.name
@@ -0,0 +1 @@
+Rothko
\ No newline at end of file
diff --git a/.idea/.idea.Rothko/.idea/indexLayout.xml b/.idea/.idea.Rothko/.idea/indexLayout.xml
new file mode 100644
index 0000000..27ba142
--- /dev/null
+++ b/.idea/.idea.Rothko/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Rothko/.idea/misc.xml b/.idea/.idea.Rothko/.idea/misc.xml
new file mode 100644
index 0000000..16d1225
--- /dev/null
+++ b/.idea/.idea.Rothko/.idea/misc.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Rothko/.idea/vcs.xml b/.idea/.idea.Rothko/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/.idea.Rothko/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Rothko/riderModule.iml b/.idea/.idea.Rothko/riderModule.iml
new file mode 100644
index 0000000..1a4e0d9
--- /dev/null
+++ b/.idea/.idea.Rothko/riderModule.iml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.vs/Rothko/v15/sqlite3/storage.ide b/.vs/Rothko/v15/sqlite3/storage.ide
new file mode 100644
index 0000000..fba15a4
Binary files /dev/null and b/.vs/Rothko/v15/sqlite3/storage.ide differ
diff --git a/.vs/Rothko/xs/UserPrefs.xml b/.vs/Rothko/xs/UserPrefs.xml
new file mode 100644
index 0000000..6a75d14
--- /dev/null
+++ b/.vs/Rothko/xs/UserPrefs.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.vs/Rothko/xs/project-cache/Rothko-Debug.json b/.vs/Rothko/xs/project-cache/Rothko-Debug.json
new file mode 100644
index 0000000..b3844c1
--- /dev/null
+++ b/.vs/Rothko/xs/project-cache/Rothko-Debug.json
@@ -0,0 +1 @@
+{"Format":1,"ProjectReferences":[],"MetadataReferences":[{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Microsoft.CSharp.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/mscorlib.dll","Aliases":[],"Framework":null},{"FilePath":"/Users/haacked/dev/haacked/rothko/packages/NullGuard.Fody.1.4.4/Lib/portable-net4+sl5+wpa81+wp8+win8+MonoAndroid16+MonoTouch40/NullGuard.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/System.Core.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/System.Data.DataSetExtensions.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/System.Data.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/System.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/System.Net.Http.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/System.Windows.Forms.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/System.Xml.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/System.Xml.Linq.dll","Aliases":[],"Framework":null}],"Files":["/Users/haacked/dev/haacked/rothko/SolutionInfo.cs","/Users/haacked/dev/haacked/rothko/src/AssemblyFacade.cs","/Users/haacked/dev/haacked/rothko/src/DependencyRegistrationHelper.cs","/Users/haacked/dev/haacked/rothko/src/DirectoryInfo.cs","/Users/haacked/dev/haacked/rothko/src/Environment.cs","/Users/haacked/dev/haacked/rothko/src/FileInfo.cs","/Users/haacked/dev/haacked/rothko/src/FileSystemInfo.cs","/Users/haacked/dev/haacked/rothko/src/FileSystemWatcher.cs","/Users/haacked/dev/haacked/rothko/src/GlobalSuppressions.cs","/Users/haacked/dev/haacked/rothko/src/Guard.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/BrowseDirectoryResult.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/Browser.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/DialogFacade.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/DirectoryFacade.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/EnumerableExtensions.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/ExceptionExtensions.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/FileFacade.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/IAssemblyFacade.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/IBrowser.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/IDialogFacade.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/DialogFacadeExtensions.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/IDirectoryFacade.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/IDirectoryInfo.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/IEnvironment.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/IFileSystemWatcher.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/IFileFacade.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/IOperatingSystem.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/IFileInfo.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/IFileSystemInfo.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/IOperatingSystemInfo.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/IRegistry.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/IRegistryKey.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/OpenDialogResult.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/RegistryExtensions.cs","/Users/haacked/dev/haacked/rothko/src/Networking/HttpClient.cs","/Users/haacked/dev/haacked/rothko/src/Networking/IHttpClient.cs","/Users/haacked/dev/haacked/rothko/src/Networking/IWebClient.cs","/Users/haacked/dev/haacked/rothko/src/Networking/WebClient.cs","/Users/haacked/dev/haacked/rothko/src/Infrastructure/SaveDialogResult.cs","/Users/haacked/dev/haacked/rothko/src/Net/HttpListenerContextWrapper.cs","/Users/haacked/dev/haacked/rothko/src/Net/HttpListenerRequestWrapper.cs","/Users/haacked/dev/haacked/rothko/src/Net/HttpListenerResponseWrapper.cs","/Users/haacked/dev/haacked/rothko/src/Net/HttpListenerWrapper.cs","/Users/haacked/dev/haacked/rothko/src/Net/IHttpListener.cs","/Users/haacked/dev/haacked/rothko/src/Net/IHttpListenerContext.cs","/Users/haacked/dev/haacked/rothko/src/Net/IHttpListenerRequest.cs","/Users/haacked/dev/haacked/rothko/src/Net/IHttpListenerResponse.cs","/Users/haacked/dev/haacked/rothko/src/Net/INetFactory.cs","/Users/haacked/dev/haacked/rothko/src/Net/NetFactory.cs","/Users/haacked/dev/haacked/rothko/src/OperatingSystemInfo.cs","/Users/haacked/dev/haacked/rothko/src/OperatingSystemFacade.cs","/Users/haacked/dev/haacked/rothko/src/Processes/IProcess.cs","/Users/haacked/dev/haacked/rothko/src/Processes/IProcessLocator.cs","/Users/haacked/dev/haacked/rothko/src/Processes/IProcessStarter.cs","/Users/haacked/dev/haacked/rothko/src/Processes/NullProcess.cs","/Users/haacked/dev/haacked/rothko/src/Processes/ProcessLocator.cs","/Users/haacked/dev/haacked/rothko/src/Processes/ProcessStarter.cs","/Users/haacked/dev/haacked/rothko/src/Processes/ProcessWrapper.cs","/Users/haacked/dev/haacked/rothko/src/Properties/AssemblyInfo.cs","/Users/haacked/dev/haacked/rothko/src/Registry.cs","/Users/haacked/dev/haacked/rothko/src/RegistryKey.cs","/Users/haacked/dev/haacked/rothko/src/Threading/IMemoryMappedFile.cs","/Users/haacked/dev/haacked/rothko/src/Threading/ISemaphore.cs","/Users/haacked/dev/haacked/rothko/src/Threading/ISystemSemaphore.cs","/Users/haacked/dev/haacked/rothko/src/Threading/MemoryMappedFileWrapper.cs","/Users/haacked/dev/haacked/rothko/src/Threading/IMemoryMappedFileFactory.cs","/Users/haacked/dev/haacked/rothko/src/Threading/MemoryMappedFileFactory.cs","/Users/haacked/dev/haacked/rothko/src/Threading/SystemSemaphore.cs","/Users/haacked/dev/haacked/rothko/src/Win32/NativeMethods.cs","/Users/haacked/dev/haacked/rothko/src/Win32/PROCESS_BASIC_INFORMATION.cs","/Users/haacked/dev/haacked/rothko/src/Win32/SafeNativeMethods.cs","/Users/haacked/dev/haacked/rothko/src/Win32/ShowWindowOption.cs","/Users/haacked/dev/haacked/rothko/src/Win32/SystemMetric.cs","/Users/haacked/dev/haacked/rothko/src/Win32/UnsafeNativeMethods.cs","/Users/haacked/dev/haacked/rothko/CodeAnalysisDictionary.xml","/Users/haacked/dev/haacked/rothko/src/FodyWeavers.xml","/Users/haacked/dev/haacked/rothko/src/key.snk","/Users/haacked/dev/haacked/rothko/src/packages.config"],"BuildActions":["Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","CodeAnalysisDictionary","Content","None","None"],"Analyzers":[],"AdditionalFiles":[],"EditorConfigFiles":[]}
\ No newline at end of file
diff --git a/.vs/Rothko/xs/project-cache/Tests-Debug.json b/.vs/Rothko/xs/project-cache/Tests-Debug.json
new file mode 100644
index 0000000..397a118
--- /dev/null
+++ b/.vs/Rothko/xs/project-cache/Tests-Debug.json
@@ -0,0 +1 @@
+{"Format":1,"ProjectReferences":[{"FilePath":"/Users/haacked/dev/haacked/rothko/src/Rothko.csproj","Aliases":[],"Framework":null}],"MetadataReferences":[{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Microsoft.CSharp.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/mscorlib.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/System.Core.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/System.Data.DataSetExtensions.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/System.Data.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/System.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/System.Xml.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/System.Xml.Linq.dll","Aliases":[],"Framework":null},{"FilePath":"/Users/haacked/dev/haacked/rothko/packages/xunit.abstractions.2.0.0/lib/net35/xunit.abstractions.dll","Aliases":[],"Framework":null},{"FilePath":"/Users/haacked/dev/haacked/rothko/packages/xunit.assert.2.1.0/lib/portable-net45+win8+wp8+wpa81/xunit.assert.dll","Aliases":[],"Framework":null},{"FilePath":"/Users/haacked/dev/haacked/rothko/packages/xunit.extensibility.core.2.1.0/lib/portable-net45+win8+wp8+wpa81/xunit.core.dll","Aliases":[],"Framework":null},{"FilePath":"/Users/haacked/dev/haacked/rothko/packages/xunit.core.2.1.0/build/_desktop/xunit.execution.desktop.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Diagnostics.Contracts.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.IO.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Dynamic.Runtime.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Runtime.Serialization.Xml.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Security.Principal.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Reflection.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.ComponentModel.EventBasedAsync.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Threading.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.ServiceModel.Http.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Text.Encoding.Extensions.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Net.NetworkInformation.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.ServiceModel.Primitives.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Reflection.Primitives.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Runtime.Numerics.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Reflection.Emit.Lightweight.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Linq.Expressions.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Runtime.InteropServices.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Text.RegularExpressions.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Threading.Tasks.Parallel.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Collections.Concurrent.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.ObjectModel.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Linq.Parallel.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Xml.XDocument.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.ComponentModel.Annotations.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Runtime.InteropServices.WindowsRuntime.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Linq.Queryable.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Resources.ResourceManager.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Collections.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Reflection.Emit.ILGeneration.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.ComponentModel.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.ServiceModel.Security.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Xml.ReaderWriter.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Threading.Tasks.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Diagnostics.Tracing.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Text.Encoding.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Globalization.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Runtime.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Xml.XmlSerializer.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Reflection.Extensions.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Runtime.Extensions.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.ServiceModel.NetTcp.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Net.Requests.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Reflection.Emit.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Runtime.Serialization.Json.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Linq.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Diagnostics.Tools.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Diagnostics.Debug.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Runtime.Serialization.Primitives.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.ServiceModel.Duplex.dll","Aliases":[],"Framework":null},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/4.5-api/Facades/System.Net.Primitives.dll","Aliases":[],"Framework":null}],"Files":["/Users/haacked/dev/haacked/rothko/Tests/DirectoryInfoTests.cs","/Users/haacked/dev/haacked/rothko/Tests/Helpers/DisposableDirectory.cs","/Users/haacked/dev/haacked/rothko/Tests/NullGuardTest.cs","/Users/haacked/dev/haacked/rothko/Tests/Properties/AssemblyInfo.cs","/Users/haacked/dev/haacked/rothko/packages/xunit.core.2.1.0/build/_desktop/xunit.execution.desktop.dll","/Users/haacked/dev/haacked/rothko/Tests/packages.config"],"BuildActions":["Compile","Compile","Compile","Compile","None","None"],"Analyzers":[],"AdditionalFiles":[],"EditorConfigFiles":[]}
\ No newline at end of file
diff --git a/.vs/Rothko/xs/sqlite3/db.lock b/.vs/Rothko/xs/sqlite3/db.lock
new file mode 100644
index 0000000..e69de29
diff --git a/.vs/Rothko/xs/sqlite3/storage.ide b/.vs/Rothko/xs/sqlite3/storage.ide
new file mode 100644
index 0000000..623ed7d
Binary files /dev/null and b/.vs/Rothko/xs/sqlite3/storage.ide differ
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..87e7d92
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,74 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of experience,
+nationality, personal appearance, race, religion, or sexual identity and
+orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at haacked@gmail.com. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
diff --git a/ReleaseNotes.md b/ReleaseNotes.md
index 18c0463..b34e11e 100644
--- a/ReleaseNotes.md
+++ b/ReleaseNotes.md
@@ -1,3 +1,3 @@
### New in 0.0.1
-* Initial release
+* Initial alpha release
diff --git a/Rothko.nuspec b/Rothko.nuspec
new file mode 100644
index 0000000..c712ad2
--- /dev/null
+++ b/Rothko.nuspec
@@ -0,0 +1,18 @@
+
+
+
+ @project@
+ @build.number@
+ @authors@
+ @authors@
+ @summary@
+ https://github.com/haacked/rothko/blob/master/LICENSE.txt
+ https://github.com/haacked/rothko
+ https://cloud.githubusercontent.com/assets/19977/4635932/4483417a-53de-11e4-8aad-7f06b2d3c46a.png
+ false
+ @description@
+ @releaseNotes@
+ Copyright Phil Haack 2015
+ dotnet abstractions
+
+
\ No newline at end of file
diff --git a/Rothko.sln b/Rothko.sln
index 8cfe41f..03c4258 100644
--- a/Rothko.sln
+++ b/Rothko.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.21005.1
+# Visual Studio 15
+VisualStudioVersion = 15.0.26730.16
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rothko", "src\Rothko.csproj", "{4A84E568-CA86-4510-8CD0-90D3EF9B65F9}"
EndProject
@@ -10,6 +10,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Meta", "Meta", "{1F038D9F-9
CodeAnalysisDictionary.xml = CodeAnalysisDictionary.xml
LICENSE-MIT.txt = LICENSE-MIT.txt
README.md = README.md
+ ReleaseNotes.md = ReleaseNotes.md
Rothko.ruleset = Rothko.ruleset
EndProjectSection
EndProject
@@ -17,8 +18,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2DC1E33B-E4FB-44C0-9DA5-96D11B41267A}"
ProjectSection(SolutionItems) = preProject
+ appveyor.yml = appveyor.yml
script\build.cmd = script\build.cmd
script\build.fsx = script\build.fsx
+ Rothko.nuspec = Rothko.nuspec
EndProjectSection
EndProject
Global
@@ -39,4 +42,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {8C5B6B0F-3329-42AF-88DF-C9C63EB69037}
+ EndGlobalSection
EndGlobal
diff --git a/Tests/DirectoryInfoTests.cs b/Tests/DirectoryInfoTests.cs
new file mode 100644
index 0000000..8da045f
--- /dev/null
+++ b/Tests/DirectoryInfoTests.cs
@@ -0,0 +1,28 @@
+using System.IO;
+using Xunit;
+using DirectoryInfo = Rothko.DirectoryInfo;
+
+public class DirectoryInfoTests
+{
+ public class TheCreateMethod
+ {
+ [Fact]
+ public void CreatesMissingParentDirectories()
+ {
+ using (var tempDir = DisposableDirectory.CreateRandomDirectory())
+ {
+ var path = Path.Combine(tempDir.FullPath, "foo", "bar", "baz");
+ var directory = new DirectoryInfo(path);
+ Assert.False(Directory.Exists(Path.Combine(tempDir.FullPath, "foo")));
+ Assert.False(Directory.Exists(Path.Combine(tempDir.FullPath, "foo", "bar")));
+ Assert.False(Directory.Exists(path));
+
+ directory.Create();
+
+ Assert.True(Directory.Exists(Path.Combine(tempDir.FullPath, "foo")));
+ Assert.True(Directory.Exists(Path.Combine(tempDir.FullPath, "foo", "bar")));
+ Assert.True(Directory.Exists(path));
+ }
+ }
+ }
+}
diff --git a/Tests/Helpers/DisposableDirectory.cs b/Tests/Helpers/DisposableDirectory.cs
new file mode 100644
index 0000000..fbea9d1
--- /dev/null
+++ b/Tests/Helpers/DisposableDirectory.cs
@@ -0,0 +1,34 @@
+using System;
+using System.IO;
+
+public sealed class DisposableDirectory : IDisposable
+{
+ readonly DirectoryInfo directory;
+
+ public static DisposableDirectory CreateRandomDirectory()
+ {
+ return CreateDirectory(GetRandomRothkoTemporaryFolder());
+ }
+
+ public static DisposableDirectory CreateDirectory(string path)
+ {
+ return new DisposableDirectory(new DirectoryInfo(path));
+ }
+
+ DisposableDirectory(DirectoryInfo directory)
+ {
+ this.directory = directory;
+ }
+
+ public string FullPath { get { return directory.FullName; } }
+
+ public void Dispose()
+ {
+ directory.Delete(true);
+ }
+
+ static string GetRandomRothkoTemporaryFolder()
+ {
+ return Path.Combine(Path.GetTempPath(), "__RothkoTestFolder-REMOVE-ME", Path.GetRandomFileName());
+ }
+}
diff --git a/Tests/NullGuardTest.cs b/Tests/NullGuardTest.cs
index b05c232..c211f1c 100644
--- a/Tests/NullGuardTest.cs
+++ b/Tests/NullGuardTest.cs
@@ -1,9 +1,9 @@
#if !DEBUG
using System;
-#endif
using Rothko;
+#endif
using Xunit;
-using Xunit.Sdk;
+using Environment = Rothko.Environment;
namespace Tests
{
@@ -12,9 +12,7 @@ public class NullGuardTest
[Fact]
public void MakeSureNullGuardIsWorking()
{
-#if DEBUG
- Assert.Throws(() => new FileInfo(null));
-#else
+#if !DEBUG
Assert.Throws(() => new FileInfo(null));
#endif
}
@@ -22,11 +20,9 @@ public void MakeSureNullGuardIsWorking()
[Fact]
public void CheckOSVersionImplementation()
{
- Environment env = new Environment();
+ var environment = new Environment();
- Assert.NotNull(env.OSVersion.Edition);
- Assert.NotNull(env.OSVersion.Name);
- Assert.True(env.OSVersion.ToString().Length > 7);
+ Assert.True(environment.OSVersion.ToString().Length > 7);
}
}
}
diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj
index a838a47..16429a0 100644
--- a/Tests/Tests.csproj
+++ b/Tests/Tests.csproj
@@ -1,5 +1,6 @@
+ DebugAnyCPU
@@ -13,6 +14,7 @@
v4.5512
+ 668ee80etrue
@@ -41,12 +43,26 @@
-
- False
- ..\packages\xunit.1.9.2\lib\net20\xunit.dll
+
+ ..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll
+ True
+
+
+ ..\packages\xunit.assert.2.1.0\lib\portable-net45+win8+wp8+wpa81\xunit.assert.dll
+ True
+
+
+ ..\packages\xunit.extensibility.core.2.1.0\lib\portable-net45+win8+wp8+wpa81\xunit.core.dll
+ True
+
+
+ ..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll
+ True
+
+
@@ -60,6 +76,12 @@
+
+
+ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
-
-
-
-
-
\ No newline at end of file
diff --git a/src/FodyWeavers.xml b/src/FodyWeavers.xml
index 9d96e0a..9321cb9 100644
--- a/src/FodyWeavers.xml
+++ b/src/FodyWeavers.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/src/GlobalSuppressions.cs b/src/GlobalSuppressions.cs
index 2a338a8..9316be8 100644
Binary files a/src/GlobalSuppressions.cs and b/src/GlobalSuppressions.cs differ
diff --git a/src/Infrastructure/BrowseDirectoryResult.cs b/src/Infrastructure/BrowseDirectoryResult.cs
new file mode 100644
index 0000000..af62e6e
--- /dev/null
+++ b/src/Infrastructure/BrowseDirectoryResult.cs
@@ -0,0 +1,58 @@
+using System;
+using NullGuard;
+
+namespace Rothko
+{
+ public struct BrowseDirectoryResult
+ {
+ readonly bool _success;
+ readonly string _directoryPath;
+
+ ///
+ /// Represents a failed browse result.
+ ///
+ public static readonly BrowseDirectoryResult Failed = new BrowseDirectoryResult();
+
+ public BrowseDirectoryResult(string directoryPath)
+ {
+ if (directoryPath.Length == 0) throw new ArgumentException("Selected path cannot be empty", "directoryPath");
+
+ _success = true;
+ _directoryPath = directoryPath;
+ }
+
+ public bool Success
+ {
+ get { return _success; }
+ }
+
+ public string DirectoryPath
+ {
+ get { return _directoryPath; }
+ }
+
+ public override bool Equals([AllowNull]object obj)
+ {
+ if (!(obj is BrowseDirectoryResult)) return false;
+ return this == ((BrowseDirectoryResult)obj);
+ }
+
+ public static bool operator ==(BrowseDirectoryResult a, BrowseDirectoryResult b)
+ {
+ return a._success == b._success && a._directoryPath == b._directoryPath;
+ }
+
+ public static bool operator !=(BrowseDirectoryResult a, BrowseDirectoryResult b)
+ {
+ return !(a == b);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ return (17327 * 67 + _success.GetHashCode()) * 67 + (_directoryPath ?? "").GetHashCode();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/Browser.cs b/src/Infrastructure/Browser.cs
new file mode 100644
index 0000000..79ba1a8
--- /dev/null
+++ b/src/Infrastructure/Browser.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+
+namespace Rothko.Infrastructure
+{
+ public class Browser : IBrowser
+ {
+ readonly IProcessStarter processStarter;
+ readonly IEnvironment environment;
+
+ public Browser(IProcessStarter processStarter, IEnvironment environment)
+ {
+ this.processStarter = processStarter;
+ this.environment = environment;
+ }
+
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
+ Justification = "We can't anticipate the type of exception it'll throw and we want to have the fallback behavior")]
+ public void OpenUrl(Uri url)
+ {
+ if (url.IsAbsoluteUri) throw new ArgumentException("URL must be an absolute uri", "url");
+
+ try
+ {
+ processStarter.Start(url.ToString(), null);
+ }
+ catch (Exception firstAttemptException)
+ {
+ try
+ {
+ var programFiles = environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFiles);
+
+ processStarter.Start(Path.Combine(programFiles, @"Internet Explorer", "iexplore.exe"),
+ url.ToString());
+ }
+ catch (Exception secondAttemptException)
+ {
+ throw new AggregateException(firstAttemptException, secondAttemptException);
+ }
+ }
+ }
+
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
+ Justification = "By design, this method should not throw.")]
+ public bool TryOpenUrl(Uri url)
+ {
+ try
+ {
+ OpenUrl(url);
+ return true;
+ }
+ catch (Exception)
+ {
+ }
+ return false;
+ }
+ }
+}
diff --git a/src/Infrastructure/DialogFacade.cs b/src/Infrastructure/DialogFacade.cs
index fe09322..58c3794 100644
--- a/src/Infrastructure/DialogFacade.cs
+++ b/src/Infrastructure/DialogFacade.cs
@@ -1,9 +1,74 @@
-using Microsoft.Win32;
+using System.Windows.Forms;
+using SaveFileDialog = Microsoft.Win32.SaveFileDialog;
namespace Rothko
{
public class DialogFacade : IDialogFacade
{
+ public DialogResult ShowMessage(
+ string text,
+ string caption,
+ MessageBoxButtons buttons,
+ MessageBoxIcon icon,
+ MessageBoxDefaultButton defaultButton,
+ MessageBoxOptions options,
+ bool displayHelpButton)
+ {
+ return MessageBox.Show(text, caption, buttons, icon, defaultButton, options, displayHelpButton);
+ }
+
+ public DialogResult ShowMessage(
+ string text,
+ string caption,
+ MessageBoxButtons buttons,
+ MessageBoxIcon icon,
+ MessageBoxDefaultButton defaultButton,
+ MessageBoxOptions options,
+ string helpFilePath)
+ {
+ return MessageBox.Show(text, caption, buttons, icon, defaultButton, options, helpFilePath);
+ }
+
+ public DialogResult ShowMessage(
+ string text,
+ string caption,
+ MessageBoxButtons buttons,
+ MessageBoxIcon icon,
+ MessageBoxDefaultButton defaultButton,
+ MessageBoxOptions options,
+ string helpFilePath,
+ HelpNavigator navigator)
+ {
+ return MessageBox.Show(text, caption, buttons, icon, defaultButton, options, helpFilePath, navigator);
+ }
+
+ public DialogResult ShowMessage(
+ string text,
+ string caption,
+ MessageBoxButtons buttons,
+ MessageBoxIcon icon,
+ MessageBoxDefaultButton defaultButton,
+ MessageBoxOptions options,
+ string helpFilePath,
+ HelpNavigator navigator,
+ object param)
+ {
+ return MessageBox.Show(text, caption, buttons, icon, defaultButton, options, helpFilePath, navigator, param);
+ }
+
+ public DialogResult ShowMessage(
+ string text,
+ string caption,
+ MessageBoxButtons buttons,
+ MessageBoxIcon icon,
+ MessageBoxDefaultButton defaultButton,
+ MessageBoxOptions options,
+ string helpFilePath,
+ string keyword)
+ {
+ return MessageBox.Show(text, caption, buttons, icon, defaultButton, options, helpFilePath, keyword);
+ }
+
public SaveDialogResult ShowSaveFileDialog(string filterPattern)
{
var dialog = new SaveFileDialog()
@@ -12,8 +77,42 @@ public SaveDialogResult ShowSaveFileDialog(string filterPattern)
};
return dialog.ShowDialog() == true
- ? new SaveDialogResult(true, dialog.FileName)
- : new SaveDialogResult(false, null);
+ ? new SaveDialogResult(dialog.FileName)
+ : SaveDialogResult.Failed;
+ }
+
+ public OpenDialogResult ShowOpenFileDialog(string filePattern, bool multiselect)
+ {
+ using (var dialog = new OpenFileDialog())
+ {
+ dialog.Multiselect = multiselect;
+ dialog.Filter = filePattern;
+ var result = dialog.ShowDialog();
+ return result == DialogResult.OK
+ ? new OpenDialogResult(dialog.FileNames)
+ : new OpenDialogResult();
+ }
+ }
+
+ public BrowseDirectoryResult BrowseForDirectory(string selectedPath, string title)
+ {
+ using (var folderBrowser = new FolderBrowserDialog())
+ {
+ folderBrowser.RootFolder = System.Environment.SpecialFolder.Desktop;
+ folderBrowser.SelectedPath = selectedPath;
+ folderBrowser.ShowNewFolderButton = false;
+
+ if (title != null)
+ {
+ folderBrowser.Description = title;
+ }
+
+ var dialogResult = folderBrowser.ShowDialog();
+
+ return dialogResult == DialogResult.OK
+ ? new BrowseDirectoryResult(folderBrowser.SelectedPath)
+ : BrowseDirectoryResult.Failed;
+ }
}
}
}
diff --git a/src/Infrastructure/DialogFacadeExtensions.cs b/src/Infrastructure/DialogFacadeExtensions.cs
new file mode 100644
index 0000000..29251da
--- /dev/null
+++ b/src/Infrastructure/DialogFacadeExtensions.cs
@@ -0,0 +1,134 @@
+using System.Windows.Forms;
+
+namespace Rothko.Extensions
+{
+ public static class DialogFacadeExtensions
+ {
+ private const string DefaultCaption = "";
+ private const MessageBoxButtons DefaultButtons = MessageBoxButtons.OK;
+ private const MessageBoxIcon DefaultIcon = MessageBoxIcon.None;
+ private const MessageBoxDefaultButton DefaultDefaultButton = MessageBoxDefaultButton.Button1;
+ private const MessageBoxOptions DefaultOptions = 0;
+ private const bool DefaultDisplayHelpButton = false;
+
+ ///
+ /// Displays a message box with specified text, caption, buttons and icon.
+ ///
+ /// The
+ /// The text to display in the message box.
+ /// One of the values.
+ public static DialogResult ShowMessage(this IDialogFacade facade, string message)
+ {
+ return facade.ShowMessage(
+ message,
+ DefaultCaption,
+ DefaultButtons,
+ DefaultIcon,
+ DefaultDefaultButton,
+ DefaultOptions,
+ DefaultDisplayHelpButton);
+ }
+
+ ///
+ /// Displays a message box with specified text, caption, buttons and icon.
+ ///
+ /// The
+ /// The text to display in the message box.
+ /// The text to display in the title bar of the message box.
+ /// One of the values.
+ public static DialogResult ShowMessage(this IDialogFacade facade, string message, string caption)
+ {
+ return facade.ShowMessage(
+ message,
+ caption,
+ DefaultButtons,
+ DefaultIcon,
+ DefaultDefaultButton,
+ DefaultOptions,
+ DefaultDisplayHelpButton);
+ }
+
+ ///
+ /// Displays a message box with specified text, caption, buttons and icon.
+ ///
+ /// The
+ /// The text to display in the message box.
+ /// The text to display in the title bar of the message box.
+ /// One of the values that specifies which
+ /// buttons to show in the message box.
+ /// One of the values.
+ public static DialogResult ShowMessage(
+ this IDialogFacade facade,
+ string message,
+ string caption,
+ MessageBoxButtons buttons)
+ {
+ return facade.ShowMessage(
+ message,
+ caption,
+ buttons,
+ DefaultIcon,
+ DefaultDefaultButton,
+ DefaultOptions,
+ DefaultDisplayHelpButton);
+ }
+
+ ///
+ /// Displays a message box with specified text, caption, buttons and icon.
+ ///
+ /// The
+ /// The text to display in the message box.
+ /// The text to display in the title bar of the message box.
+ /// One of the values that specifies which
+ /// buttons to show in the message box.
+ /// One of the values that specifies which
+ /// icon to display in the message box.
+ public static DialogResult ShowMessage(
+ this IDialogFacade facade,
+ string message,
+ string caption,
+ MessageBoxButtons buttons,
+ MessageBoxIcon icon)
+ {
+ return facade.ShowMessage(
+ message,
+ caption,
+ buttons,
+ icon,
+ DefaultDefaultButton,
+ DefaultOptions,
+ DefaultDisplayHelpButton);
+ }
+
+ ///
+ /// Displays a message box with specified text, caption, buttons and icon.
+ ///
+ /// The
+ /// The text to display in the message box.
+ /// The text to display in the title bar of the message box.
+ /// One of the values that specifies which
+ /// buttons to show in the message box.
+ /// One of the values that specifies which
+ /// icon to display in the message box.
+ /// One of the values that specifies
+ /// the default button for the message box.
+ /// One of the values.
+ public static DialogResult ShowMessage(
+ this IDialogFacade facade,
+ string message,
+ string caption,
+ MessageBoxButtons buttons,
+ MessageBoxIcon icon,
+ MessageBoxDefaultButton defaultButton)
+ {
+ return facade.ShowMessage(
+ message,
+ caption,
+ buttons,
+ icon,
+ defaultButton,
+ DefaultOptions,
+ DefaultDisplayHelpButton);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/DirectoryFacade.cs b/src/Infrastructure/DirectoryFacade.cs
index 84c583a..c359f7e 100644
--- a/src/Infrastructure/DirectoryFacade.cs
+++ b/src/Infrastructure/DirectoryFacade.cs
@@ -1,19 +1,77 @@
using System;
+using System.Collections.Generic;
using System.Globalization;
using System.IO;
+using NullGuard;
namespace Rothko
{
public class DirectoryFacade : IDirectoryFacade
{
- public IDirectoryInfo GetDirectory(string path)
+ public IDirectoryInfo CreateDirectory(string path)
{
- return new DirectoryInfo(path);
+ return DirectoryInfo.Wrap(Directory.CreateDirectory(path));
}
- public IDirectoryInfo CreateDirectory(string path)
+ public void DeleteDirectory(string path)
+ {
+ Directory.Delete(path);
+ }
+
+ public void DeleteDirectory(string path, bool recursive)
+ {
+ Directory.Delete(path, recursive);
+ }
+
+ public bool DirectoryExists(string path)
{
- return new DirectoryInfo(Directory.CreateDirectory(path));
+ return Directory.Exists(path);
+ }
+
+ public string GetCurrentDirectory()
+ {
+ return Directory.GetCurrentDirectory();
+ }
+
+ public IEnumerable EnumerateDirectories(string path)
+ {
+ return Directory.EnumerateDirectories(path);
+ }
+
+ public IEnumerable EnumerateDirectories(string path, string searchPattern)
+ {
+ return Directory.EnumerateDirectories(path, searchPattern);
+ }
+
+ public IEnumerable EnumerateDirectories(string path, string searchPattern, SearchOption searchOption)
+ {
+ return Directory.EnumerateDirectories(path, searchPattern, searchOption);
+ }
+
+ public IEnumerable EnumerateFiles(string path)
+ {
+ return EnumerateFiles(path, "*.*");
+ }
+
+ public IEnumerable EnumerateFiles(string path, string searchPattern)
+ {
+ return EnumerateFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
+ }
+
+ public IEnumerable EnumerateFiles(string path, string searchPattern, SearchOption searchOption)
+ {
+ return Directory.EnumerateFiles(path, searchPattern, searchOption);
+ }
+
+ [return: AllowNull]
+ public IDirectoryInfo GetParent(string path)
+ {
+ return DirectoryInfo.Wrap(Directory.GetParent(path));
+ }
+
+ public IDirectoryInfo GetDirectory(string path)
+ {
+ return new DirectoryInfo(path);
}
public bool Exists(string path)
diff --git a/src/Infrastructure/EnumerableExtensions.cs b/src/Infrastructure/EnumerableExtensions.cs
index c4f0809..bc48e93 100644
--- a/src/Infrastructure/EnumerableExtensions.cs
+++ b/src/Infrastructure/EnumerableExtensions.cs
@@ -10,5 +10,10 @@ public static IDictionary ToGenericDictionary(this I
{
return dictionary.Keys.Cast().ToDictionary(key => key, key => (TValue) dictionary[key]);
}
+
+ public static IEnumerable WhereNotNull(this IEnumerable source) where T : class
+ {
+ return source.Where(item => item != null);
+ }
}
}
\ No newline at end of file
diff --git a/src/Infrastructure/FileFacade.cs b/src/Infrastructure/FileFacade.cs
index 214a1f4..58fe54c 100644
--- a/src/Infrastructure/FileFacade.cs
+++ b/src/Infrastructure/FileFacade.cs
@@ -1,12 +1,75 @@
-using System.IO;
+using System.Collections.Generic;
+using System.IO;
+using System.Security.AccessControl;
+using System.Text;
namespace Rothko
{
public class FileFacade : IFileFacade
{
+ public FileStream Create(string path)
+ {
+ return File.Create(path);
+ }
+
+ public FileStream Create(string path, int bufferSize)
+ {
+ return File.Create(path, bufferSize);
+ }
+
+ public FileStream Create(string path, int bufferSize, FileOptions options)
+ {
+ return File.Create(path, bufferSize, options);
+ }
+
+ public FileStream Create(string path, int bufferSize, FileOptions options, FileSecurity fileSecurity)
+ {
+ return File.Create(path, bufferSize, options, fileSecurity);
+ }
+
+ public bool Exists(string path)
+ {
+ return File.Exists(path);
+ }
+
+ public IFileInfo GetFile(string path)
+ {
+ return FileInfo.Wrap(new System.IO.FileInfo(path));
+ }
+
public void WriteAllText(string path, string contents)
{
File.WriteAllText(path, contents);
}
+
+ public void WriteAllText(string path, string contents, Encoding encoding)
+ {
+ File.WriteAllText(path, contents, encoding);
+ }
+
+ public void Copy(string sourceFileName, string destFileName, bool overwrite)
+ {
+ File.Copy(sourceFileName, destFileName, overwrite);
+ }
+
+ public void Move(string sourceFileName, string destFileName)
+ {
+ File.Move(sourceFileName, destFileName);
+ }
+
+ public IEnumerable ReadLines(string path, Encoding encoding)
+ {
+ return File.ReadLines(path, encoding);
+ }
+
+ public string ReadAllText(string path, Encoding encoding)
+ {
+ return File.ReadAllText(path, encoding);
+ }
+
+ public void Delete(string path)
+ {
+ File.Delete(path);
+ }
}
}
diff --git a/src/Infrastructure/IBrowser.cs b/src/Infrastructure/IBrowser.cs
new file mode 100644
index 0000000..ac6cf0c
--- /dev/null
+++ b/src/Infrastructure/IBrowser.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Rothko
+{
+ public interface IBrowser
+ {
+ ///
+ /// Opens the user's default browser to the specified URL.
+ ///
+ ///
+ void OpenUrl(Uri url);
+
+ ///
+ /// Opens the user's default browser to the specified URL and returns false if it was unable to.
+ ///
+ ///
+ bool TryOpenUrl(Uri url);
+ }
+}
+
diff --git a/src/Infrastructure/IDialogFacade.cs b/src/Infrastructure/IDialogFacade.cs
index 5cfd095..064a1e0 100644
--- a/src/Infrastructure/IDialogFacade.cs
+++ b/src/Infrastructure/IDialogFacade.cs
@@ -1,33 +1,168 @@
-using System.Diagnostics.CodeAnalysis;
+using System.Windows.Forms;
namespace Rothko
{
public interface IDialogFacade
{
+ ///
+ /// Displays a message box with specified text, caption, buttons and icon.
+ ///
+ /// The text to display in the message box.
+ /// The text to display in the title bar of the message box.
+ /// One of the values that specifies which
+ /// buttons to show in the message box.
+ /// One of the values that specifies which
+ /// icon to display in the message box.
+ /// One of the values that specifies
+ /// the default button for the message box.
+ /// One of the values that specifies which
+ /// display and association options will be used for the message box. You may
+ /// pass in 0 if you wish to use the defaults.
+ /// true to show the Help button; otherwise, false. The default is false.
+ /// One of the values.
+ DialogResult ShowMessage(
+ string text,
+ string caption,
+ MessageBoxButtons buttons,
+ MessageBoxIcon icon,
+ MessageBoxDefaultButton defaultButton,
+ MessageBoxOptions options,
+ bool displayHelpButton);
+
+ ///
+ /// Displays a message box with specified text, caption, buttons and icon.
+ ///
+ /// The text to display in the message box.
+ /// The text to display in the title bar of the message box.
+ /// One of the values that specifies which
+ /// buttons to show in the message box.
+ /// One of the values that specifies which
+ /// icon to display in the message box.
+ /// One of the values that specifies
+ /// the default button for the message box.
+ /// One of the values that specifies which
+ /// display and association options will be used for the message box. You may
+ /// pass in 0 if you wish to use the defaults.
+ /// The path and name of the Help file to display when the user clicks the Help
+ /// button.
+ /// One of the values.
+ DialogResult ShowMessage(
+ string text,
+ string caption,
+ MessageBoxButtons buttons,
+ MessageBoxIcon icon,
+ MessageBoxDefaultButton defaultButton,
+ MessageBoxOptions options,
+ string helpFilePath);
+
+ ///
+ /// Displays a message box with specified text, caption, buttons and icon.
+ ///
+ /// The text to display in the message box.
+ /// The text to display in the title bar of the message box.
+ /// One of the values that specifies which
+ /// buttons to show in the message box.
+ /// One of the values that specifies which
+ /// icon to display in the message box.
+ /// One of the values that specifies
+ /// the default button for the message box.
+ /// One of the values that specifies which
+ /// display and association options will be used for the message box. You may
+ /// pass in 0 if you wish to use the defaults.
+ /// The path and name of the Help file to display when the user clicks the Help
+ /// button.
+ /// One of the values.
+ /// One of the values.
+ DialogResult ShowMessage(
+ string text,
+ string caption,
+ MessageBoxButtons buttons,
+ MessageBoxIcon icon,
+ MessageBoxDefaultButton defaultButton,
+ MessageBoxOptions options,
+ string helpFilePath,
+ HelpNavigator navigator);
+
+ ///
+ /// Displays a message box with specified text, caption, buttons and icon.
+ ///
+ /// The text to display in the message box.
+ /// The text to display in the title bar of the message box.
+ /// One of the values that specifies which
+ /// buttons to show in the message box.
+ /// One of the values that specifies which
+ /// icon to display in the message box.
+ /// One of the values that specifies
+ /// the default button for the message box.
+ /// One of the values that specifies which
+ /// display and association options will be used for the message box. You may
+ /// pass in 0 if you wish to use the defaults.
+ /// The path and name of the Help file to display when the user clicks the Help
+ /// button.
+ /// One of the values.
+ /// The numeric ID of the Help topic to display when the user clicks the Help
+ /// button.
+ /// One of the values.
+ DialogResult ShowMessage(
+ string text,
+ string caption,
+ MessageBoxButtons buttons,
+ MessageBoxIcon icon,
+ MessageBoxDefaultButton defaultButton,
+ MessageBoxOptions options,
+ string helpFilePath,
+ HelpNavigator navigator,
+ object param);
+
+ ///
+ /// Displays a message box with specified text, caption, buttons and icon.
+ ///
+ /// The text to display in the message box.
+ /// The text to display in the title bar of the message box.
+ /// One of the values that specifies which
+ /// buttons to show in the message box.
+ /// One of the values that specifies which
+ /// icon to display in the message box.
+ /// One of the values that specifies
+ /// the default button for the message box.
+ /// One of the values that specifies which
+ /// display and association options will be used for the message box. You may
+ /// pass in 0 if you wish to use the defaults.
+ /// The path and name of the Help file to display when the user clicks the Help
+ /// button.
+ /// The Help keyword to display when the user clicks the Help button.
+ /// One of the values.
+ DialogResult ShowMessage(
+ string text,
+ string caption,
+ MessageBoxButtons buttons,
+ MessageBoxIcon icon,
+ MessageBoxDefaultButton defaultButton,
+ MessageBoxOptions options,
+ string helpFilePath,
+ string keyword);
+
+ ///
+ /// Displays a save file dialog and returns the result of the user's interaction with the dialog.
+ ///
+ /// Pattern used to filter the files shown
+ ///
SaveDialogResult ShowSaveFileDialog(string filterPattern);
- }
- [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes",
- Justification = "TODO: Should this even be a struct?")]
- public struct SaveDialogResult
- {
- readonly bool _success;
- readonly string _fileName;
-
- public SaveDialogResult(bool success, string chosenFileName)
- {
- _success = success;
- _fileName = chosenFileName;
- }
-
- public bool Success
- {
- get { return _success; }
- }
-
- public string FileName
- {
- get { return _fileName; }
- }
+ ///
+ /// Displays an open file dialog and returns the result of the user's interaction with the dialog.
+ ///
+ /// Pattern used to filter the files shown.
+ /// Indicates whether the dialog box allows multiple files to be selected.
+ /// A indicating the action taken by the user.
+ OpenDialogResult ShowOpenFileDialog(string filePattern, bool multiselect);
+
+ ///
+ /// Opens a standard Windows browse directory and returns the result.
+ ///
+ /// The default selected path
+ /// The title to show on the dialog
+ ///
+ BrowseDirectoryResult BrowseForDirectory(string selectedPath, string title);
}
}
diff --git a/src/Infrastructure/IDirectoryFacade.cs b/src/Infrastructure/IDirectoryFacade.cs
index e0811cf..5114c16 100644
--- a/src/Infrastructure/IDirectoryFacade.cs
+++ b/src/Infrastructure/IDirectoryFacade.cs
@@ -1,33 +1,88 @@
-using System.IO;
+using System.Collections.Generic;
+using System.IO;
namespace Rothko
{
public interface IDirectoryFacade
{
- ///
- /// Returns a representing the directory at the specified path.
- ///
- /// Path to the directory
- /// A instance.
- IDirectoryInfo GetDirectory(string path);
-
- ///
- /// Creates all directories and subdirectories in the specified path.
- ///
- ///
- /// If the directory already exists, it just returns the directory.
- ///
- /// Path to the directory
- /// A instance.
+ /// Creates all directories and subdirectories in the specified path.
+ /// The directory path to create.
+ /// An object that represents the directory for the specified path.
+ ///
+ /// The directory specified by is a file.
+ /// -or-The network name is not known.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ /// is a zero-length string, contains only white space, or contains one or
+ /// more invalid characters as defined by .
+ /// -or- is prefixed with, or contains only a colon character (:).
+ ///
+ /// is null.
+ ///
+ /// The specified path, file name, or both exceed the system-defined maximum length. For example, on
+ /// Windows-based platforms, paths must be less than 248 characters and file names must be less than
+ /// 260 characters.
+ ///
+ ///
+ /// The specified path is invalid (for example, it is on an unmapped drive).
+ ///
+ ///
+ /// contains a colon character (:) that is not part of a drive label ("C:\").
+ ///
+ /// 1
+ ///
+ ///
+ ///
IDirectoryInfo CreateDirectory(string path);
+ /// Deletes an empty directory from a specified path.
+ ///
+ /// The name of the empty directory to remove. This directory must be writable or empty.
+ ///
+ ///
+ /// A file with the same name and location specified by exists.
+ /// -or-The directory is the application's current working directory.
+ /// -or-The directory specified by is not empty.
+ /// -or-The directory is read-only or contains a read-only file.
+ /// -or-The directory is being used by another process.
+ /// -or-There is an open handle on the directory, and the operating system is Windows XP or earlier.
+ /// This open handle can result from directories. For more information, see How to: Enumerate
+ /// Directories and Files.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ /// is a zero-length string, contains only white space, or contains one
+ /// or more invalid characters as defined by .
+ ///
+ /// is null.
+ ///
+ /// The specified path, file name, or both exceed the system-defined maximum length. For example, on
+ /// Windows-based platforms, paths must be less than 248 characters and file names must be less than
+ /// 260 characters.
+ ///
+ ///
+ /// does not exist or could not be found.
+ /// -or- refers to a file instead of a directory.
+ /// -or-The specified path is invalid (for example, it is on an unmapped drive).
+ ///
+ /// 1
+ ///
+ ///
+ ///
+ void DeleteDirectory(string path);
+
///
/// Returns true if the directory exists at the specified path.
///
/// Path to the directory
/// True if the directory exists, otherwise false.
bool Exists(string path);
-
+
///
/// Returns true if the directory is empty
///
@@ -35,5 +90,379 @@ public interface IDirectoryFacade
/// Thrown if the directory doesn't exist
///
bool IsEmpty(string path);
+
+ /// Deletes an empty directory from a specified path.
+ /// The name of the directory to remove.
+ ///
+ /// true to remove directories, subdirectories, and files in ;
+ /// otherwise, false.
+ ///
+ ///
+ /// A file with the same name and location specified by exists.
+ /// -or-The directory specified by is read-only, or
+ /// is false and is not an empty directory.
+ /// -or-The directory is the application's current working directory.
+ /// -or-The directory contains a read-only file.
+ /// -or-The directory is being used by another process.There is an open handle on the directory or
+ /// on one of its files, and the operating system is Windows XP or earlier. This open handle can
+ /// result from enumerating directories and files. For more information, see How to: Enumerate
+ /// Directories and Files.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ /// is a zero-length string, contains only white space, or contains one or
+ /// more invalid characters as defined by .
+ ///
+ /// is null.
+ ///
+ /// The specified path, file name, or both exceed the system-defined maximum length. For example, on
+ /// Windows-based platforms, paths must be less than 248 characters and file names must be less than
+ /// 260 characters.
+ ///
+ ///
+ /// does not exist or could not be found.
+ /// -or- refers to a file instead of a directory.
+ /// -or-The specified path is invalid (for example, it is on an unmapped drive).
+ ///
+ /// 1
+ ///
+ ///
+ ///
+ void DeleteDirectory(string path, bool recursive);
+
+ /// Determines whether the given path refers to an existing directory on disk.
+ /// true if refers to an existing directory; otherwise, false.
+ /// The path to test.
+ /// 1
+ ///
+ ///
+ ///
+ bool DirectoryExists(string path);
+
+ /// Gets a representing the specified path.
+ /// The path of the directory to get.
+ /// An object that represents the directory for the specified path.
+ /// is null.
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ /// contains invalid characters such as ", >, <, or |.
+ ///
+ ///
+ /// The specified path, file name, or both exceed the system-defined maximum length. For example, on
+ /// Windows-based platforms, paths must be less than 248 characters, and file names must be less than
+ /// 260 characters. The specified path, file name, or both are too long.
+ ///
+ IDirectoryInfo GetDirectory(string path);
+
+ /// Gets the current working directory of the application.
+ ///
+ /// A string that contains the path of the current working directory, and does not end with a
+ /// backslash (\).
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ /// The operating system is Windows CE, which does not have current directory functionality.This
+ /// method is available in the .NET Compact Framework, but is not currently supported.
+ ///
+ /// 1
+ ///
+ ///
+ ///
+ string GetCurrentDirectory();
+
+ ///
+ /// Returns an enumerable collection of directory names in a specified path.
+ ///
+ ///
+ /// The relative or absolute to the directory to search. This string is not
+ /// case-sensitive.
+ ///
+ ///
+ /// An enumerable collection of the full names (including paths) for the directories in the directory
+ /// specified by .
+ ///
+ ///
+ /// is a zero-length string, contains only white space, or contains invalid
+ /// characters. You can query for invalid characters by using the
+ /// method.
+ ///
+ /// is null.
+ ///
+ /// is invalid, such as referring to an unmapped drive.
+ ///
+ /// is a file name.
+ ///
+ /// The specified path, file name, or combined exceed the system-defined maximum length. For example,
+ /// on Windows-based platforms, paths must be less than 248 characters and file names must be less
+ /// than 260 characters.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ IEnumerable EnumerateDirectories(string path);
+
+ ///
+ /// Returns an enumerable collection of directory names that match a search pattern in a specified path.
+ ///
+ ///
+ /// The relative or absolute to the directory to search. This string is not
+ /// case-sensitive.
+ ///
+ ///
+ /// The search string to match against the names of directories in . This parameter can
+ /// contain a combination of valid literal path and wildcard (* and ?) characters (see Remarks), but doesn't
+ /// support regular expressions.
+ ///
+ ///
+ /// An enumerable collection of the full names (including paths) for the directories in the directory
+ /// specified by .
+ ///
+ ///
+ /// is a zero-length string, contains only white space, or contains invalid
+ /// characters as defined by .
+ /// -or- does not contain a valid pattern.
+ ///
+ ///
+ /// is null.
+ /// -or- is null.
+ ///
+ ///
+ /// is invalid, such as referring to an unmapped drive.
+ ///
+ /// is a file name.
+ ///
+ /// The specified path, file name, or combined exceed the system-defined maximum length. For example,
+ /// on Windows-based platforms, paths must be less than 248 characters and file names must be less
+ /// than 260 characters.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ IEnumerable EnumerateDirectories(string path, string searchPattern);
+
+ ///
+ /// Returns an enumerable collection of directory names that match a search pattern in a specified path, and
+ /// optionally searches subdirectories.
+ ///
+ ///
+ /// The relative or absolute to the directory to search. This string is not
+ /// case-sensitive.
+ ///
+ ///
+ /// The search string to match against the names of directories in . This parameter can
+ /// contain a combination of valid literal path and wildcard (* and ?) characters (see Remarks), but doesn't
+ /// support regular expressions.
+ ///
+ ///
+ /// One of the enumeration values that specifies whether the search operation should include only the current
+ /// directory or should include all subdirectories.
+ ///
+ ///
+ /// An enumerable collection of the full names (including paths) for the directories in the directory
+ /// specified by .
+ ///
+ ///
+ /// is a zero-length string, contains only white space, or contains invalid
+ /// characters as defined by .
+ /// -or- does not contain a valid pattern.
+ ///
+ ///
+ /// is null.
+ /// -or- is null.
+ ///
+ ///
+ /// is not a valid value.
+ ///
+ ///
+ /// is invalid, such as referring to an unmapped drive.
+ ///
+ /// is a file name.
+ ///
+ /// The specified path, file name, or combined exceed the system-defined maximum length. For example,
+ /// on Windows-based platforms, paths must be less than 248 characters and file names must be less
+ /// than 260 characters.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ IEnumerable EnumerateDirectories(string path, string searchPattern, SearchOption searchOption);
+
+ /// Returns an enumerable collection of file names in a specified path.
+ /// The directory to search.
+ ///
+ /// An enumerable collection of the full names (including paths) for the files in the directory
+ /// specified by .
+ ///
+ ///
+ /// is a zero-length string, contains only white space, or contains invalid
+ /// characters as defined by .
+ ///
+ /// is null.
+ ///
+ /// is invalid, such as referring to an unmapped drive.
+ ///
+ /// is a file name.
+ ///
+ /// The specified path, file name, or combined exceed the system-defined maximum length. For example,
+ /// on Windows-based platforms, paths must be less than 248 characters and file names must be less
+ /// than 260 characters.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ IEnumerable EnumerateFiles(string path);
+
+ ///
+ /// Returns an enumerable collection of file names that match a search pattern in a specified path.
+ ///
+ /// The directory to search.
+ ///
+ /// The search string to match against the names of directories in .
+ ///
+ ///
+ /// An enumerable collection of the full names (including paths) for the files in the directory
+ /// specified by and that match the specified search pattern.
+ ///
+ ///
+ /// is a zero-length string, contains only white space, or contains invalid
+ /// characters as defined by .
+ /// -or- does not contain a valid pattern.
+ ///
+ ///
+ /// is null.
+ /// -or- is null.
+ ///
+ ///
+ /// is invalid, such as referring to an unmapped drive.
+ ///
+ /// is a file name.
+ ///
+ /// The specified path, file name, or combined exceed the system-defined maximum length. For example,
+ /// on Windows-based platforms, paths must be less than 248 characters and file names must be less
+ /// than 260 characters.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ IEnumerable EnumerateFiles(string path, string searchPattern);
+
+ ///
+ /// Returns an enumerable collection of file names that match a search pattern in a specified path,
+ /// and optionally searches subdirectories.
+ ///
+ /// The directory to search.
+ ///
+ /// The search string to match against the names of directories in .
+ ///
+ ///
+ /// One of the enumeration values that specifies whether the search operation should include only the
+ /// current directory or should include all subdirectories.The default value is
+ /// .
+ ///
+ ///
+ /// An enumerable collection of the full names (including paths) for the files in the directory
+ /// specified by and that match the specified search pattern and option.
+ ///
+ ///
+ /// is a zero-length string, contains only white space, or contains invalid
+ /// characters as defined by .
+ /// -or- does not contain a valid pattern.
+ ///
+ ///
+ /// is null.
+ /// -or- is null.
+ ///
+ ///
+ /// is not a valid value.
+ ///
+ ///
+ /// is invalid, such as referring to an unmapped drive.
+ ///
+ /// is a file name.
+ ///
+ /// The specified path, file name, or combined exceed the system-defined maximum length. For example,
+ /// on Windows-based platforms, paths must be less than 248 characters and file names must be less
+ /// than 260 characters.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ IEnumerable EnumerateFiles(string path, string searchPattern, SearchOption searchOption);
+
+ ///
+ /// Retrieves the parent directory of the specified path, including both absolute and relative paths.
+ ///
+ ///
+ ///
+ /// The parameter is permitted to specify relative or absolute path information. Relative path
+ /// information is interpreted as relative to the current working directory. To obtain the current working
+ /// directory, see .
+ ///
+ ///
+ /// Trailing spaces are removed from the end of the parameter before getting the directory.
+ ///
+ ///
+ /// The string returned by this method consists of all characters in the path up to, but not including, the
+ /// last or . For
+ /// example, passing the path "C:\Directory\SubDirectory\test.txt" to GetParent returns
+ /// "C:\Directory\SubDirectory". Passing "C:\Directory\SubDirectory" returns "C:\Directory". However,
+ /// passing "C:\Directory\SubDirectory\" returns "C:\Directory\SubDirectory", because the ending directory
+ /// separator is after "SubDirectory".
+ ///
+ ///
+ /// The path parameter is not case-sensitive.
+ ///
+ /// For a list of common I/O tasks, see Common I/O Tasks.
+ ///
+ /// The path for which to retrieve the parent directory.
+ ///
+ /// The parent directory, or null if path is the root directory, including the root of a UNC server or
+ /// share name.
+ ///
+ ///
+ /// The directory specified by is read-only.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ ///
+ /// is a zero-length string, contains only white space, or contains one or more invalid characters. You can
+ /// query for invalid characters with the method.
+ ///
+ /// is null.
+ ///
+ /// The specified path, file name, or both exceed the system-defined maximum length. For example, on
+ /// Windows-based platforms, paths must be less than 248 characters and file names must be less than
+ /// 260 characters.
+ ///
+ ///
+ /// The specified was not found.
+ ///
+ IDirectoryInfo GetParent(string path);
}
}
diff --git a/src/Infrastructure/IDirectoryInfo.cs b/src/Infrastructure/IDirectoryInfo.cs
index 18cc342..fd0e2ef 100644
--- a/src/Infrastructure/IDirectoryInfo.cs
+++ b/src/Infrastructure/IDirectoryInfo.cs
@@ -394,7 +394,7 @@ public interface IDirectoryInfo : IFileSystemInfo
///
///
/// A object that encapsulates the
- /// access control rules for the file described by the parameter.
+ /// access control rules for the file.
///
///
/// One of the values that
@@ -456,8 +456,7 @@ public interface IDirectoryInfo : IFileSystemInfo
/// object to the directory described by the current object.
///
///
- /// An object that describes an ACL entry to apply to the directory described by the
- /// parameter.
+ /// An object that describes an ACL entry to apply to the directory.
///
///
/// The parameter is null.
diff --git a/src/Infrastructure/IEnvironment.cs b/src/Infrastructure/IEnvironment.cs
index 827f0bc..3ce10f4 100644
--- a/src/Infrastructure/IEnvironment.cs
+++ b/src/Infrastructure/IEnvironment.cs
@@ -23,7 +23,7 @@ public interface IEnvironment
string NewLine { get; }
- IOperatingSystem OSVersion { get; }
+ IOperatingSystemInfo OSVersion { get; }
int ProcessorCount { get; }
diff --git a/src/Infrastructure/IFileFacade.cs b/src/Infrastructure/IFileFacade.cs
index 394c0bb..b31b183 100644
--- a/src/Infrastructure/IFileFacade.cs
+++ b/src/Infrastructure/IFileFacade.cs
@@ -1,7 +1,456 @@
-namespace Rothko
+using System.Collections.Generic;
+using System.IO;
+using System.Security.AccessControl;
+using System.Text;
+
+namespace Rothko
{
public interface IFileFacade
{
+ ///
+ /// Creates or overwrites the specified file with the specified buffer size,
+ /// file options, and file security.
+ ///
+ /// The name of the file.
+ ///
+ /// A new file with the specified buffer size, file options, and file security.
+ ///
+ ///
+ /// The caller does not have the required permission.-or- specified a file
+ /// that is read-only.-or-System.IO.FileOptions.Encrypted is specified for options
+ /// and file encryption is not supported on the current platform.
+ ///
+ ///
+ /// is a zero-length string, contains only white space, or contains one
+ /// or more invalid characters as defined by System.IO.Path.InvalidPathChars.
+ ///
+ /// is null.
+ ///
+ /// The specified , file name, or both exceed the system-defined maximum
+ /// length. For example, on Windows-based platforms, paths must be less than
+ /// 248 characters, and file names must be less than 260 characters.
+ ///
+ ///
+ /// The specified is invalid (for example, it is on an unmapped drive).
+ ///
+ /// An I/O error occurred while creating the file.
+ /// is in an invalid format.
+ ///
+ /// The caller does not have the required permission.-or- specified a file
+ /// that is read-only.
+ ///
+ FileStream Create(string path);
+
+ ///
+ /// Creates or overwrites the specified file with the specified buffer size,
+ /// file options, and file security.
+ ///
+ /// The name of the file.
+ /// The number of bytes buffered for reads and writes to the file.
+ ///
+ /// A new file with the specified buffer size, file options, and file security.
+ ///
+ ///
+ /// The caller does not have the required permission.-or- specified a file
+ /// that is read-only.-or-System.IO.FileOptions.Encrypted is specified for options
+ /// and file encryption is not supported on the current platform.
+ ///
+ ///
+ /// is a zero-length string, contains only white space, or contains one
+ /// or more invalid characters as defined by System.IO.Path.InvalidPathChars.
+ ///
+ /// is null.
+ ///
+ /// The specified , file name, or both exceed the system-defined maximum
+ /// length. For example, on Windows-based platforms, paths must be less than
+ /// 248 characters, and file names must be less than 260 characters.
+ ///
+ ///
+ /// The specified is invalid (for example, it is on an unmapped drive).
+ ///
+ /// An I/O error occurred while creating the file.
+ /// is in an invalid format.
+ ///
+ /// The caller does not have the required permission.-or- specified a file
+ /// that is read-only.
+ ///
+ FileStream Create(string path, int bufferSize);
+
+ ///
+ /// Creates or overwrites the specified file with the specified buffer size,
+ /// file options, and file security.
+ ///
+ /// The name of the file.
+ /// The number of bytes buffered for reads and writes to the file.
+ ///
+ /// One of the values that describes how to create or overwrite
+ /// the file
+ ///
+ ///
+ /// A new file with the specified buffer size, file options, and file security.
+ ///
+ ///
+ /// The caller does not have the required permission.-or- specified a file
+ /// that is read-only.-or-System.IO.FileOptions.Encrypted is specified for options
+ /// and file encryption is not supported on the current platform.
+ ///
+ ///
+ /// is a zero-length string, contains only white space, or contains one
+ /// or more invalid characters as defined by System.IO.Path.InvalidPathChars.
+ ///
+ /// is null.
+ ///
+ /// The specified , file name, or both exceed the system-defined maximum
+ /// length. For example, on Windows-based platforms, paths must be less than
+ /// 248 characters, and file names must be less than 260 characters.
+ ///
+ ///
+ /// The specified is invalid (for example, it is on an unmapped drive).
+ ///
+ /// An I/O error occurred while creating the file.
+ /// is in an invalid format.
+ ///
+ /// The caller does not have the required permission.-or- specified a file
+ /// that is read-only.
+ ///
+ FileStream Create(string path, int bufferSize, FileOptions options);
+
+ ///
+ /// Creates or overwrites the specified file with the specified buffer size,
+ /// file options, and file security.
+ ///
+ /// The name of the file.
+ /// The number of bytes buffered for reads and writes to the file.
+ ///
+ /// One of the values that describes how to create or overwrite
+ /// the file
+ ///
+ ///
+ /// One of the values that determines
+ /// the access control and audit security for the file.
+ ///
+ ///
+ /// A new file with the specified buffer size, file options, and file security.
+ ///
+ ///
+ /// The caller does not have the required permission.-or- specified a file
+ /// that is read-only.-or-System.IO.FileOptions.Encrypted is specified for options
+ /// and file encryption is not supported on the current platform.
+ ///
+ ///
+ /// is a zero-length string, contains only white space, or contains one
+ /// or more invalid characters as defined by System.IO.Path.InvalidPathChars.
+ ///
+ /// is null.
+ ///
+ /// The specified , file name, or both exceed the system-defined maximum
+ /// length. For example, on Windows-based platforms, paths must be less than
+ /// 248 characters, and file names must be less than 260 characters.
+ ///
+ ///
+ /// The specified is invalid (for example, it is on an unmapped drive).
+ ///
+ /// An I/O error occurred while creating the file.
+ /// is in an invalid format.
+ ///
+ /// The caller does not have the required permission.-or- specified a file
+ /// that is read-only.
+ ///
+ FileStream Create(string path, int bufferSize, FileOptions options, FileSecurity fileSecurity);
+
+ /// Determines whether the specified file exists.
+ /// The file to check.
+ ///
+ /// true if the caller has the required permissions and path contains the name
+ /// of an existing file; otherwise, false. This method also returns false if
+ /// path is null, an invalid path, or a zero-length string. If the caller does
+ /// not have sufficient permissions to read the specified file, no exception
+ /// is thrown and the method returns false regardless of the existence of path.
+ ///
+ bool Exists(string path);
+
+ /// Gets a representing the specified path.
+ /// The path of the file to get.
+ /// An object that represents the file for the specified path.
+ /// is null.
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ /// contains invalid characters such as ", >, <, or |.
+ ///
+ ///
+ /// The specified path, file name, or both exceed the system-defined maximum length. For example, on
+ /// Windows-based platforms, paths must be less than 248 characters, and file names must be less than
+ /// 260 characters. The specified path, file name, or both are too long.
+ ///
+ IFileInfo GetFile(string path);
+
+ ///
+ /// Gets a representing the specified path.
+ ///
+ /// The path of the file to get.
+ /// The string to write to the file.
+ /// is null or is null.
+ ///
+ /// contains invalid characters such as ", >, <, or |.
+ ///
+ ///
+ /// The specified is invalid (for example, it is on an unmapped drive).
+ ///
+ ///
+ /// The specified , file name, or both exceed the system-defined maximum length. For example, on
+ /// Windows-based platforms, paths must be less than 248 characters, and file names must be less than
+ /// 260 characters. The specified path, file name, or both are too long.
+ ///
+ ///
+ /// An I/O error occurred while opening the file.
+ ///
+ ///
+ /// specified a file that is read-only.-or- This operation is not supported
+ /// on the current platform.-or- path specified a directory.-or- The caller does
+ /// not have the required permission.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
void WriteAllText(string path, string contents);
+
+ ///
+ /// Gets a representing the specified path.
+ ///
+ /// The path of the file to get.
+ /// The string to write to the file.
+ /// The encoding that is applied to the contents of the file.
+ /// is null or is null.
+ ///
+ /// contains invalid characters such as ", >, <, or |.
+ ///
+ ///
+ /// The specified is invalid (for example, it is on an unmapped drive).
+ ///
+ ///
+ /// The specified , file name, or both exceed the system-defined maximum length. For example, on
+ /// Windows-based platforms, paths must be less than 248 characters, and file names must be less than
+ /// 260 characters. The specified path, file name, or both are too long.
+ ///
+ ///
+ /// An I/O error occurred while opening the file.
+ ///
+ ///
+ /// specified a file that is read-only.-or- This operation is not supported
+ /// on the current platform.-or- path specified a directory.-or- The caller does
+ /// not have the required permission.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ void WriteAllText(string path, string contents, Encoding encoding);
+
+ ///
+ /// Copies an existing file to a new file. Overwriting a file of the same name
+ /// is allowed.
+ ///
+ /// The file to copy.
+ /// The name of the destination file. This cannot be a directory.
+ /// true if the destination file can be overwritten; otherwise, false.
+ ///
+ /// The caller does not have the required permission. -or-destFileName is read-only.
+ ///
+ ///
+ /// or is a zero-length string,
+ /// contains only white space, or contains one or more invalid characters as defined by
+ /// System.IO.Path.InvalidPathChars.-or- sourceFileName or destFileName specifies a directory.
+ ///
+ ///
+ /// or sourceFileName or destFileName is null.
+ ///
+ ///
+ /// The path specified in or , file name,
+ /// or both exceed the system-defined maximum length. For example, on Windows-based platforms, paths must be
+ /// less than 248 characters, and file names must be less than 260 characters. The specified path, file
+ /// name, or both are too long.
+ ///
+ ///
+ /// The path specified in or is invalid
+ /// (for example, it is on an unmapped drive).
+ ///
+ ///
+ /// was not found.
+ ///
+ ///
+ /// exists and overwrite is false.-or- An I/O error has occurred.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ void Copy(string sourceFileName, string destFileName, bool overwrite);
+
+
+ ///
+ /// Moves a specified file to a new location, providing the option to specify
+ /// a new file name.
+ ///
+ /// The file to copy.
+ /// The name of the destination file. This cannot be a directory.
+ ///
+ /// The caller does not have the required permission. -or-destFileName is read-only.
+ ///
+ ///
+ /// or is a zero-length string,
+ /// contains only white space, or contains one or more invalid characters as defined by
+ /// System.IO.Path.InvalidPathChars.-or- sourceFileName or destFileName specifies a directory.
+ ///
+ ///
+ /// or sourceFileName or destFileName is null.
+ ///
+ ///
+ /// The path specified in or , file name,
+ /// or both exceed the system-defined maximum length. For example, on Windows-based platforms, paths must be
+ /// less than 248 characters, and file names must be less than 260 characters. The specified path, file
+ /// name, or both are too long.
+ ///
+ ///
+ /// The path specified in or is invalid
+ /// (for example, it is on an unmapped drive).
+ ///
+ ///
+ /// was not found.
+ ///
+ ///
+ /// exists and overwrite is false.-or- An I/O error has occurred.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ void Move(string sourceFileName, string destFileName);
+
+ ///
+ /// Read the lines of a file that has a specified encoding.
+ ///
+ /// The file to check.
+ /// The encoding that is applied to the contents of the file.
+ ///
+ /// All the lines of the file, or the lines that are the result of a query.
+ ///
+ ///
+ /// is a zero-length string, contains only white space, or contains one
+ /// or more invalid characters as defined by the System.IO.Path.GetInvalidPathChars()
+ /// method.
+ ///
+ /// is null.
+ ///
+ /// The specified is invalid (for example, it is on an unmapped drive).
+ ///
+ ///
+ /// was not found.
+ ///
+ ///
+ /// The specified , file name, or both exceed the system-defined maximum length. For example, on
+ /// Windows-based platforms, paths must be less than 248 characters, and file names must be less than
+ /// 260 characters. The specified path, file name, or both are too long.
+ ///
+ ///
+ /// An I/O error occurred while opening the file.
+ ///
+ ///
+ /// specified a file that is read-only.-or- This operation is not supported
+ /// on the current platform.-or- path specified a directory.-or- The caller does
+ /// not have the required permission.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ IEnumerable ReadLines(string path, Encoding encoding);
+
+ ///
+ /// Opens a file, reads all lines of the file with the specified encoding, and
+ /// then closes the file.
+ ///
+ /// The file to check.
+ /// The encoding that is applied to the contents of the file.
+ ///
+ /// All the lines of the file, or the lines that are the result of a query.
+ ///
+ ///
+ /// is a zero-length string, contains only white space, or contains one
+ /// or more invalid characters as defined by the System.IO.Path.GetInvalidPathChars()
+ /// method.
+ ///
+ /// is null.
+ ///
+ /// The specified is invalid (for example, it is on an unmapped drive).
+ ///
+ ///
+ /// was not found.
+ ///
+ ///
+ /// The specified , file name, or both exceed the system-defined maximum length. For example, on
+ /// Windows-based platforms, paths must be less than 248 characters, and file names must be less than
+ /// 260 characters. The specified path, file name, or both are too long.
+ ///
+ ///
+ /// An I/O error occurred while opening the file.
+ ///
+ ///
+ /// specified a file that is read-only.-or- This operation is not supported
+ /// on the current platform.-or- path specified a directory.-or- The caller does
+ /// not have the required permission.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ string ReadAllText(string path, Encoding encoding);
+
+ ///
+ /// Deletes the specified file.
+ ///
+ /// The file to check.
+ ///
+ /// is a zero-length string, contains only white space, or contains one
+ /// or more invalid characters as defined by the System.IO.Path.GetInvalidPathChars()
+ /// method.
+ ///
+ /// is null.
+ ///
+ /// The specified is invalid (for example, it is on an unmapped drive).
+ ///
+ ///
+ /// was not found.
+ ///
+ ///
+ /// The specified , file name, or both exceed the system-defined maximum length. For example, on
+ /// Windows-based platforms, paths must be less than 248 characters, and file names must be less than
+ /// 260 characters. The specified path, file name, or both are too long.
+ ///
+ ///
+ /// The specified file is in use. -or-There is an open handle on the file, and
+ /// the operating system is Windows XP or earlier. This open handle can result
+ /// from enumerating directories and files. For more information, see How to:
+ /// Enumerate Directories and Files.
+ ///
+ ///
+ // The caller does not have the required permission.-or- is a directory.-or-
+ // path specified a read-only file.
+ ///
+ ///
+ /// is in an invalid format.
+ ///
+ ///
+ /// The caller does not have the required permission.
+ ///
+ void Delete(string path);
}
}
diff --git a/src/Infrastructure/IFileSystemFacade.cs b/src/Infrastructure/IFileSystemFacade.cs
deleted file mode 100644
index c7f105d..0000000
--- a/src/Infrastructure/IFileSystemFacade.cs
+++ /dev/null
@@ -1,274 +0,0 @@
-using System.Collections.Generic;
-
-namespace Rothko
-{
- public interface IFileSystemFacade
- {
- /// Creates all directories and subdirectories in the specified path.
- /// The directory path to create.
- /// An object that represents the directory for the specified path.
- ///
- /// The directory specified by is a file.
- /// -or-The network name is not known.
- ///
- ///
- /// The caller does not have the required permission.
- ///
- ///
- /// is a zero-length string, contains only white space, or contains one or
- /// more invalid characters as defined by .
- /// -or- is prefixed with, or contains only a colon character (:).
- ///
- /// is null.
- ///
- /// The specified path, file name, or both exceed the system-defined maximum length. For example, on
- /// Windows-based platforms, paths must be less than 248 characters and file names must be less than
- /// 260 characters.
- ///
- ///
- /// The specified path is invalid (for example, it is on an unmapped drive).
- ///
- ///
- /// contains a colon character (:) that is not part of a drive label ("C:\").
- ///
- /// 1
- ///
- ///
- ///
- IDirectoryInfo CreateDirectory(string path);
-
- /// Deletes an empty directory from a specified path.
- ///
- /// The name of the empty directory to remove. This directory must be writable or empty.
- ///
- ///
- /// A file with the same name and location specified by exists.
- /// -or-The directory is the application's current working directory.
- /// -or-The directory specified by is not empty.
- /// -or-The directory is read-only or contains a read-only file.
- /// -or-The directory is being used by another process.
- /// -or-There is an open handle on the directory, and the operating system is Windows XP or earlier.
- /// This open handle can result from directories. For more information, see How to: Enumerate
- /// Directories and Files.
- ///
- ///
- /// The caller does not have the required permission.
- ///
- ///
- /// is a zero-length string, contains only white space, or contains one
- /// or more invalid characters as defined by .
- ///
- /// is null.
- ///
- /// The specified path, file name, or both exceed the system-defined maximum length. For example, on
- /// Windows-based platforms, paths must be less than 248 characters and file names must be less than
- /// 260 characters.
- ///
- ///
- /// does not exist or could not be found.
- /// -or- refers to a file instead of a directory.
- /// -or-The specified path is invalid (for example, it is on an unmapped drive).
- ///
- /// 1
- ///
- ///
- ///
- void DeleteDirectory(string path);
-
- /// Deletes an empty directory from a specified path.
- /// The name of the directory to remove.
- ///
- /// true to remove directories, subdirectories, and files in ;
- /// otherwise, false.
- ///
- ///
- /// A file with the same name and location specified by exists.
- /// -or-The directory specified by is read-only, or
- /// is false and is not an empty directory.
- /// -or-The directory is the application's current working directory.
- /// -or-The directory contains a read-only file.
- /// -or-The directory is being used by another process.There is an open handle on the directory or
- /// on one of its files, and the operating system is Windows XP or earlier. This open handle can
- /// result from enumerating directories and files. For more information, see How to: Enumerate
- /// Directories and Files.
- ///
- ///
- /// The caller does not have the required permission.
- ///
- ///
- /// is a zero-length string, contains only white space, or contains one or
- /// more invalid characters as defined by .
- ///
- /// is null.
- ///
- /// The specified path, file name, or both exceed the system-defined maximum length. For example, on
- /// Windows-based platforms, paths must be less than 248 characters and file names must be less than
- /// 260 characters.
- ///
- ///
- /// does not exist or could not be found.
- /// -or- refers to a file instead of a directory.
- /// -or-The specified path is invalid (for example, it is on an unmapped drive).
- ///
- /// 1
- ///
- ///
- ///
- void DeleteDirectory(string path, bool recursive);
-
- /// Determines whether the given path refers to an existing directory on disk.
- /// true if refers to an existing directory; otherwise, false.
- /// The path to test.
- /// 1
- ///
- ///
- ///
- bool DirectoryExists(string path);
-
- /// Gets a representing the specified path.
- /// The path of the directory to get.
- /// An object that represents the directory for the specified path.
- /// is null.
- ///
- /// The caller does not have the required permission.
- ///
- ///
- /// contains invalid characters such as ", >, <, or |.
- ///
- ///
- /// The specified path, file name, or both exceed the system-defined maximum length. For example, on
- /// Windows-based platforms, paths must be less than 248 characters, and file names must be less than
- /// 260 characters. The specified path, file name, or both are too long.
- ///
- IDirectoryInfo GetDirectory(string path);
-
- /// Gets the current working directory of the application.
- ///
- /// A string that contains the path of the current working directory, and does not end with a
- /// backslash (\).
- ///
- ///
- /// The caller does not have the required permission.
- ///
- ///
- /// The operating system is Windows CE, which does not have current directory functionality.This
- /// method is available in the .NET Compact Framework, but is not currently supported.
- ///
- /// 1
- ///
- ///
- ///
- string GetCurrentDirectory();
-
- /// Returns an enumerable collection of file names in a specified path.
- /// The directory to search.
- ///
- /// An enumerable collection of the full names (including paths) for the files in the directory
- /// specified by .
- ///
- ///
- /// is a zero-length string, contains only white space, or contains invalid
- /// characters as defined by .
- ///
- /// is null.
- ///
- /// is invalid, such as referring to an unmapped drive.
- ///
- /// is a file name.
- ///
- /// The specified path, file name, or combined exceed the system-defined maximum length. For example,
- /// on Windows-based platforms, paths must be less than 248 characters and file names must be less
- /// than 260 characters.
- ///
- ///
- /// The caller does not have the required permission.
- ///
- ///
- /// The caller does not have the required permission.
- ///
- IEnumerable EnumerateFiles(string path);
-
- ///
- /// Returns an enumerable collection of file names that match a search pattern in a specified path.
- ///
- /// The directory to search.
- ///
- /// The search string to match against the names of directories in .
- ///
- ///
- /// An enumerable collection of the full names (including paths) for the files in the directory
- /// specified by and that match the specified search pattern.
- ///
- ///
- /// is a zero-length string, contains only white space, or contains invalid
- /// characters as defined by .
- /// -or- does not contain a valid pattern.
- ///
- ///
- /// is null.
- /// -or- is null.
- ///
- ///
- /// is invalid, such as referring to an unmapped drive.
- ///
- /// is a file name.
- ///
- /// The specified path, file name, or combined exceed the system-defined maximum length. For example,
- /// on Windows-based platforms, paths must be less than 248 characters and file names must be less
- /// than 260 characters.
- ///
- ///
- /// The caller does not have the required permission.
- ///
- ///
- /// The caller does not have the required permission.
- ///
- IEnumerable EnumerateFiles(string path, string searchPattern);
-
- ///
- /// Returns an enumerable collection of file names that match a search pattern in a specified path,
- /// and optionally searches subdirectories.
- ///
- /// The directory to search.
- ///
- /// The search string to match against the names of directories in .
- ///
- ///
- /// One of the enumeration values that specifies whether the search operation should include only the
- /// current directory or should include all subdirectories.The default value is
- /// .
- ///
- ///
- /// An enumerable collection of the full names (including paths) for the files in the directory
- /// specified by and that match the specified search pattern and option.
- ///
- ///
- /// is a zero-length string, contains only white space, or contains invalid
- /// characters as defined by .
- /// -or- does not contain a valid pattern.
- ///
- ///
- /// is null.
- /// -or- is null.
- ///
- ///
- /// is not a valid value.
- ///
- ///
- /// is invalid, such as referring to an unmapped drive.
- ///
- /// is a file name.
- ///
- /// The specified path, file name, or combined exceed the system-defined maximum length. For example,
- /// on Windows-based platforms, paths must be less than 248 characters and file names must be less
- /// than 260 characters.
- ///
- ///
- /// The caller does not have the required permission.
- ///
- ///
- /// The caller does not have the required permission.
- ///
- IEnumerable EnumerateFiles(string path, string searchPattern, System.IO.SearchOption searchOption);
- }
-}
diff --git a/src/Infrastructure/IOperatingSystem.cs b/src/Infrastructure/IOperatingSystem.cs
index 979481b..f9f87b5 100644
--- a/src/Infrastructure/IOperatingSystem.cs
+++ b/src/Infrastructure/IOperatingSystem.cs
@@ -1,15 +1,17 @@
-using System;
-using System.Runtime.Serialization;
-
-namespace Rothko
+namespace Rothko
{
- public interface IOperatingSystem : ICloneable, ISerializable
+ public interface IOperatingSystem
{
- PlatformID Platform { get; }
- string ServicePack { get; }
- Version Version { get; }
- string VersionString { get; }
- string Name { get; }
- string Edition { get; }
+ IAssemblyFacade Assembly { get; }
+ IDialogFacade Dialog { get; }
+ IDirectoryFacade Directory { get; }
+ IEnvironment Environment { get; }
+ IFileFacade File { get; }
+ IMemoryMappedFileFactory MemoryMappedFiles { get; }
+ INetFactory Net { get; }
+ IProcessLocator ProcessLocator { get; }
+ IProcessStarter ProcessStarter { get; }
+ IRegistry Registry { get; }
+ IBrowser Browser { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/Infrastructure/IOperatingSystemFacade.cs b/src/Infrastructure/IOperatingSystemFacade.cs
deleted file mode 100644
index 4da5728..0000000
--- a/src/Infrastructure/IOperatingSystemFacade.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace Rothko
-{
- public interface IOperatingSystemFacade
- {
- IAssemblyFacade Assembly { get; }
- IDialogFacade Dialog { get; }
- IDirectoryFacade Directory { get; }
- IEnvironment Environment { get; }
- IFileFacade File { get; }
- IMemoryMappedFileFactory MemoryMappedFiles { get; }
- IProcessLocator ProcessLocator { get; }
- IProcessStarter ProcessStarter { get; }
- IRegistry Registry { get; }
- }
-}
diff --git a/src/Infrastructure/IOperatingSystemInfo.cs b/src/Infrastructure/IOperatingSystemInfo.cs
new file mode 100644
index 0000000..3f98cad
--- /dev/null
+++ b/src/Infrastructure/IOperatingSystemInfo.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace Rothko
+{
+ public interface IOperatingSystemInfo : ICloneable, ISerializable
+ {
+ ///
+ /// Gets a enumeration value that identifies the operating system platform.
+ ///
+ PlatformID Platform { get; }
+
+ ///
+ /// Gets the service pack version represented by this OperatingSystem object.
+ ///
+ string ServicePack { get; }
+
+ ///
+ /// Gets a object that identifies the operating system.
+ ///
+ ///
+ /// For this to work properly for Windows 8.1 and later, be sure to specify the supported operating systems
+ /// https://msdn.microsoft.com/en-us/library/windows/desktop/dn481241(v=vs.85).aspx
+ ///
+ Version Version { get; }
+
+ ///
+ /// Gets the concatenated string representation of the platform identifier, version, and service pack that are
+ /// currently installed on the operating system.
+ ///
+ string VersionString { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/OpenDialogResult.cs b/src/Infrastructure/OpenDialogResult.cs
new file mode 100644
index 0000000..1bd8918
--- /dev/null
+++ b/src/Infrastructure/OpenDialogResult.cs
@@ -0,0 +1,54 @@
+namespace Rothko
+{
+ using System.Collections.Generic;
+ using System.Linq;
+ using NullGuard;
+
+ public struct OpenDialogResult
+ {
+ readonly bool _success;
+ readonly IEnumerable _fileNames;
+
+ public static readonly OpenDialogResult Failed = new OpenDialogResult();
+
+ public OpenDialogResult(IEnumerable chosenFileNames)
+ {
+ _success = true;
+ _fileNames = chosenFileNames;
+ }
+
+ public bool Success
+ {
+ get { return _success; }
+ }
+
+ public IEnumerable FileNames
+ {
+ get { return _fileNames; }
+ }
+
+ public override bool Equals([AllowNull]object obj)
+ {
+ if (!(obj is OpenDialogResult)) return false;
+ return this == ((OpenDialogResult)obj);
+ }
+
+ public static bool operator ==(OpenDialogResult a, OpenDialogResult b)
+ {
+ return a._success == b._success && a._fileNames.SequenceEqual(b._fileNames);
+ }
+
+ public static bool operator !=(OpenDialogResult a, OpenDialogResult b)
+ {
+ return !(a == b);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ return (17327 * 67 + _success.GetHashCode()) * 67 + (_fileNames ?? Enumerable.Empty()).GetHashCode();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/SaveDialogResult.cs b/src/Infrastructure/SaveDialogResult.cs
new file mode 100644
index 0000000..4969123
--- /dev/null
+++ b/src/Infrastructure/SaveDialogResult.cs
@@ -0,0 +1,52 @@
+using NullGuard;
+
+namespace Rothko
+{
+ public struct SaveDialogResult
+ {
+ readonly bool _success;
+ readonly string _fileName;
+
+ public static readonly SaveDialogResult Failed = new SaveDialogResult();
+
+ public SaveDialogResult(string chosenFileName)
+ {
+ _success = true;
+ _fileName = chosenFileName;
+ }
+
+ public bool Success
+ {
+ get { return _success; }
+ }
+
+ public string FileName
+ {
+ get { return _fileName; }
+ }
+
+ public override bool Equals([AllowNull]object obj)
+ {
+ if (!(obj is SaveDialogResult)) return false;
+ return this == ((SaveDialogResult)obj);
+ }
+
+ public static bool operator ==(SaveDialogResult a, SaveDialogResult b)
+ {
+ return a._success == b._success && a._fileName == b._fileName;
+ }
+
+ public static bool operator !=(SaveDialogResult a, SaveDialogResult b)
+ {
+ return !(a == b);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ return (17327 * 67 + _success.GetHashCode()) * 67 + (_fileName ?? "").GetHashCode();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Net/HttpListenerContextWrapper.cs b/src/Net/HttpListenerContextWrapper.cs
new file mode 100644
index 0000000..333dfe3
--- /dev/null
+++ b/src/Net/HttpListenerContextWrapper.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Net;
+using System.Net.WebSockets;
+using System.Security.Principal;
+using System.Threading.Tasks;
+
+namespace Rothko.Net
+{
+ public class HttpListenerContextWrapper : IHttpListenerContext, IDisposable
+ {
+ readonly HttpListenerContext inner;
+
+ public HttpListenerContextWrapper(HttpListenerContext inner)
+ {
+ this.inner = inner;
+ Request = new HttpListenerRequestWrapper(inner.Request);
+ Response = new HttpListenerResponseWrapper(inner.Response);
+ }
+
+ public IHttpListenerRequest Request { get; }
+
+ public IHttpListenerResponse Response { get; }
+
+ public IPrincipal User => inner.User;
+
+ public Task AcceptWebSocketAsync(string subProtocol)
+ {
+ return inner.AcceptWebSocketAsync(subProtocol);
+ }
+
+ public Task AcceptWebSocketAsync(string subProtocol, TimeSpan keepAliveInterval)
+ {
+ return inner.AcceptWebSocketAsync(subProtocol, keepAliveInterval);
+ }
+
+ public Task AcceptWebSocketAsync(string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval)
+ {
+ return inner.AcceptWebSocketAsync(subProtocol, receiveBufferSize, keepAliveInterval);
+ }
+
+ public Task AcceptWebSocketAsync(string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval,
+ ArraySegment internalBuffer)
+ {
+ return inner.AcceptWebSocketAsync(subProtocol, receiveBufferSize, keepAliveInterval, internalBuffer);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Response.Dispose();
+ }
+ }
+ }
+}
diff --git a/src/Net/HttpListenerRequestWrapper.cs b/src/Net/HttpListenerRequestWrapper.cs
new file mode 100644
index 0000000..a181f34
--- /dev/null
+++ b/src/Net/HttpListenerRequestWrapper.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.IO;
+using System.Net;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Rothko
+{
+ public class HttpListenerRequestWrapper : IHttpListenerRequest
+ {
+ readonly HttpListenerRequest inner;
+
+ public HttpListenerRequestWrapper(HttpListenerRequest inner)
+ {
+ this.inner = inner;
+ }
+
+ public IEnumerable AcceptTypes => inner.AcceptTypes;
+
+ public int ClientCertificateError => inner.ClientCertificateError;
+
+ public Encoding ContentEncoding => inner.ContentEncoding;
+
+ public long ContentLength64 => inner.ContentLength64;
+
+ public string ContentType => inner.ContentType;
+
+ public CookieCollection Cookies => inner.Cookies;
+
+ public bool HasEntityBody => inner.HasEntityBody;
+
+ public NameValueCollection Headers => inner.Headers;
+
+ public string HttpMethod => inner.HttpMethod;
+
+ public Stream InputStream => inner.InputStream;
+
+ public bool IsAuthenticated => inner.IsAuthenticated;
+
+ public bool IsLocal => inner.IsLocal;
+
+ public bool IsSecureConnection => inner.IsSecureConnection;
+
+ public bool IsWebSocketRequest => inner.IsWebSocketRequest;
+
+ public bool KeepAlive => inner.KeepAlive;
+
+ public IPEndPoint LocalEndPoint => inner.LocalEndPoint;
+
+ public Version ProtocolVersion => inner.ProtocolVersion;
+
+ public NameValueCollection QueryString => inner.QueryString;
+
+ public string RawUrl => inner.RawUrl;
+
+ public IPEndPoint RemoteEndPoint => inner.RemoteEndPoint;
+
+ public Guid RequestTraceIdentifier => inner.RequestTraceIdentifier;
+
+ public string ServiceName => inner.ServiceName;
+
+ public TransportContext TransportContext => inner.TransportContext;
+
+ public Uri Url => inner.Url;
+
+ public Uri UrlReferrer => inner.UrlReferrer;
+
+ public string UserAgent => inner.UserAgent;
+
+ public string UserHostAddress => inner.UserHostAddress;
+
+ public string UserHostName => inner.UserHostName;
+
+ public IEnumerable UserLanguages => inner.UserLanguages;
+
+ public IAsyncResult BeginGetClientCertificate(AsyncCallback requestCallback, object state)
+ {
+ return inner.BeginGetClientCertificate(requestCallback, state);
+ }
+
+ public X509Certificate2 EndGetClientCertificate(IAsyncResult asyncResult)
+ {
+ return inner.EndGetClientCertificate(asyncResult);
+ }
+
+ public X509Certificate2 GetClientCertificate()
+ {
+ return inner.GetClientCertificate();
+ }
+
+ public Task GetClientCertificateAsync()
+ {
+ return inner.GetClientCertificateAsync();
+ }
+ }
+}
diff --git a/src/Net/HttpListenerResponseWrapper.cs b/src/Net/HttpListenerResponseWrapper.cs
new file mode 100644
index 0000000..8840014
--- /dev/null
+++ b/src/Net/HttpListenerResponseWrapper.cs
@@ -0,0 +1,119 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Text;
+
+namespace Rothko.Net
+{
+ public class HttpListenerResponseWrapper : IHttpListenerResponse
+ {
+ private HttpListenerResponse inner;
+
+ public HttpListenerResponseWrapper(HttpListenerResponse inner)
+ {
+ this.inner = inner;
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ public Encoding ContentEncoding
+ {
+ get { return inner.ContentEncoding; }
+ set { inner.ContentEncoding = value; }
+ }
+
+ public long ContentLength64
+ {
+ get { return inner.ContentLength64; }
+ set { inner.ContentLength64 = value; }
+ }
+
+ public string ContentType
+ {
+ get { return inner.ContentType; }
+ set { inner.ContentType = value; }
+ }
+
+ public CookieCollection Cookies
+ {
+ get { return inner.Cookies; }
+ set { inner.Cookies = value; }
+ }
+
+ public WebHeaderCollection Headers
+ {
+ get { return inner.Headers; }
+ set { inner.Headers = value; }
+ }
+
+ public bool KeepAlive
+ {
+ get { return inner.KeepAlive; }
+ set { inner.KeepAlive = value; }
+ }
+
+ public Stream OutputStream => inner.OutputStream;
+
+ public Version ProtocolVersion
+ {
+ get { return inner.ProtocolVersion; }
+ set { inner.ProtocolVersion = value; }
+ }
+
+ public string RedirectLocation
+ {
+ get { return inner.RedirectLocation; }
+ set { inner.RedirectLocation = value; }
+ }
+
+ public bool SendChunked
+ {
+ get { return inner.SendChunked; }
+ set { inner.SendChunked = value; }
+ }
+
+ public int StatusCode
+ {
+ get { return inner.StatusCode; }
+ set { inner.StatusCode = value; }
+ }
+
+ public string StatusDescription
+ {
+ get { return inner.StatusDescription; }
+ set { inner.StatusDescription = value; }
+ }
+
+ public void Abort() => inner.Abort();
+
+ public void AddHeader(string name, string value) => inner.AddHeader(name, value);
+
+ public void AppendCookie(Cookie cookie) => inner.AppendCookie(cookie);
+
+ public void AppendHeader(string name, string value) => inner.AppendHeader(name, value);
+
+ public void Close() => inner.Close();
+
+ public void Close(byte[] responseEntity, bool willBlock) => inner.Close(responseEntity, willBlock);
+
+ public void CopyFrom(HttpListenerResponse templateResponse) => inner.CopyFrom(templateResponse);
+
+ public void Redirect(string url) => inner.Redirect(url);
+
+ public void Redirect(Uri url) => inner.Redirect(url.ToString());
+
+ public void SetCookie(Cookie cookie) => inner.SetCookie(cookie);
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ ((IDisposable)inner).Dispose();
+ }
+ }
+ }
+}
diff --git a/src/Net/HttpListenerWrapper.cs b/src/Net/HttpListenerWrapper.cs
new file mode 100644
index 0000000..ad7b66d
--- /dev/null
+++ b/src/Net/HttpListenerWrapper.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Net;
+using System.Security.Authentication.ExtendedProtection;
+using System.Threading.Tasks;
+using Rothko.Net;
+
+namespace Rothko
+{
+ public class HttpListenerWrapper : IHttpListener
+ {
+ readonly HttpListener inner;
+
+ public HttpListenerWrapper(HttpListener inner)
+ {
+ this.inner = inner;
+ }
+
+ public AuthenticationSchemes AuthenticationSchemes
+ {
+ get { return inner.AuthenticationSchemes; }
+ set { inner.AuthenticationSchemes = value; }
+ }
+
+ public AuthenticationSchemeSelector AuthenticationSchemeSelectorDelegate
+ {
+ get { return inner.AuthenticationSchemeSelectorDelegate; }
+ set { inner.AuthenticationSchemeSelectorDelegate = value; }
+ }
+
+ public ServiceNameCollection DefaultServiceNames => inner.DefaultServiceNames;
+
+ public ExtendedProtectionPolicy ExtendedProtectionPolicy
+ {
+ get { return inner.ExtendedProtectionPolicy; }
+ set { inner.ExtendedProtectionPolicy = value; }
+ }
+
+ public HttpListener.ExtendedProtectionSelector ExtendedProtectionSelectorDelegate
+ {
+ get { return inner.ExtendedProtectionSelectorDelegate; }
+ set { inner.ExtendedProtectionSelectorDelegate = value; }
+ }
+
+ public bool IgnoreWriteExceptions
+ {
+ get { return inner.IgnoreWriteExceptions; }
+ set { inner.IgnoreWriteExceptions = value; }
+ }
+
+ public bool IsListening => inner.IsListening;
+
+ public HttpListenerPrefixCollection Prefixes => inner.Prefixes;
+
+ public string Realm
+ {
+ get { return inner.Realm; }
+ set { inner.Realm = value; }
+ }
+
+ public HttpListenerTimeoutManager TimeoutManager => inner.TimeoutManager;
+
+ public bool UnsafeConnectionNtlmAuthentication
+ {
+ get { return inner.UnsafeConnectionNtlmAuthentication; }
+ set { inner.UnsafeConnectionNtlmAuthentication = value; }
+ }
+
+ public void Abort() => inner.Abort();
+ public IAsyncResult BeginGetContext(AsyncCallback callback, object state) => inner.BeginGetContext(callback, state);
+ public void Close() => inner.Close();
+
+ public IHttpListenerContext EndGetContext(IAsyncResult asyncResult)
+ {
+ return new HttpListenerContextWrapper(inner.EndGetContext(asyncResult));
+ }
+
+ public IHttpListenerContext GetContext()
+ {
+ return new HttpListenerContextWrapper(inner.GetContext());
+ }
+
+ public async Task GetContextAsync()
+ {
+ return new HttpListenerContextWrapper(await inner.GetContextAsync());
+ }
+
+ public void Start() => inner.Start();
+ public void Stop() => inner.Stop();
+ }
+}
diff --git a/src/Net/IHttpListener.cs b/src/Net/IHttpListener.cs
new file mode 100644
index 0000000..982484b
--- /dev/null
+++ b/src/Net/IHttpListener.cs
@@ -0,0 +1,296 @@
+using System;
+using System.Threading.Tasks;
+using System.Net;
+using System.Security.Authentication.ExtendedProtection;
+
+namespace Rothko
+{
+ ///
+ /// Provides a simple, programmatically controlled HTTP protocol listener.
+ ///
+ public interface IHttpListener
+ {
+ ///
+ /// Gets or sets the scheme used to authenticate clients.
+ ///
+ ///
+ /// A bitwise combination of System.Net.AuthenticationSchemes enumeration values
+ /// that indicates how clients are to be authenticated. The default value is
+ /// .
+ ///
+ ///
+ /// This object has been closed.
+ ///
+ AuthenticationSchemes AuthenticationSchemes { get; set; }
+
+ ///
+ /// Gets or sets the delegate called to determine the protocol used to authenticate
+ /// clients.
+ ///
+ ///
+ /// An System.Net.AuthenticationSchemeSelector delegate that invokes the method used
+ /// to select an authentication protocol. The default value is null.
+ ///
+ ///
+ /// This object has been closed.
+ ///
+ AuthenticationSchemeSelector AuthenticationSchemeSelectorDelegate { get; set; }
+
+ ///
+ /// Gets a default list of Service Provider Names (SPNs) as determined by registered
+ /// prefixes.
+ ///
+ ///
+ /// A System.Security.Authentication.ExtendedProtection.ServiceNameCollection that
+ /// contains a list of SPNs.
+ ///
+ ServiceNameCollection DefaultServiceNames { get; }
+
+ ///
+ /// Get or set the System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy
+ /// to use for extended protection for a session.
+ ///
+ ///
+ /// A System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy
+ /// that specifies the policy to use for extended protection.
+ ///
+ ///
+ /// An attempt was made to set the System.Net.HttpListener.ExtendedProtectionPolicy
+ /// property, but the System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy.CustomChannelBinding
+ /// property was not null.
+ ///
+ ///
+ /// An attempt was made to set the System.Net.HttpListener.ExtendedProtectionPolicy
+ /// property to null.
+ ///
+ ///
+ /// An attempt was made to set the System.Net.HttpListener.ExtendedProtectionPolicy
+ /// property after the System.Net.HttpListener.Start method was already called.
+ ///
+ ///
+ /// This object has been closed.
+ ///
+ ///
+ /// The System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy.PolicyEnforcement
+ /// property was set to System.Security.Authentication.ExtendedProtection.PolicyEnforcement.Always
+ /// on a platform that does not support extended protection.
+ ///
+ ExtendedProtectionPolicy ExtendedProtectionPolicy { get; set; }
+
+ ///
+ /// Get or set the delegate called to determine the System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy
+ /// to use for each request.
+ ///
+ ///
+ /// A System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy
+ /// that specifies the policy to use for extended protection.
+ ///
+ ///
+ /// An attempt was made to set the System.Net.HttpListener.ExtendedProtectionSelectorDelegate
+ /// property, but the System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy.CustomChannelBinding
+ /// property must be null.
+ ///
+ ///
+ /// An attempt was made to set the System.Net.HttpListener.ExtendedProtectionSelectorDelegate
+ /// property to null.
+ ///
+ ///
+ /// An attempt was made to set the System.Net.HttpListener.ExtendedProtectionSelectorDelegate
+ /// property after the System.Net.HttpListener.Start method was already called.
+ ///
+ ///
+ /// This object has been closed.
+ ///
+ ///
+ /// An attempt was made to set the System.Net.HttpListener.ExtendedProtectionSelectorDelegate
+ /// property on a platform that does not support extended protection.
+ ///
+ HttpListener.ExtendedProtectionSelector ExtendedProtectionSelectorDelegate { get; set; }
+
+ ///
+ /// Gets or sets a System.Boolean value that specifies whether your application receives
+ /// exceptions that occur when an System.Net.HttpListener sends the response to the
+ /// client.
+ ///
+ ///
+ /// true if this System.Net.HttpListener should not return exceptions that occur
+ /// when sending the response to the client; otherwise false. The default value is
+ /// false.
+ ///
+ ///
+ /// This object has been closed.
+ ///
+ bool IgnoreWriteExceptions { get; set; }
+
+ ///
+ /// Gets a value that indicates whether System.Net.HttpListener has been started.
+ ///
+ ///
+ /// true if the System.Net.HttpListener was started; otherwise, false.
+ ///
+ bool IsListening { get; }
+
+ ///
+ /// Gets the Uniform Resource Identifier (URI) prefixes handled by this System.Net.HttpListener
+ /// object.
+ ///
+ ///
+ /// An System.Net.HttpListenerPrefixCollection that contains the URI prefixes that
+ /// this System.Net.HttpListener object is configured to handle.
+ ///
+ ///
+ /// This object has been closed.
+ ///
+ HttpListenerPrefixCollection Prefixes { get; }
+
+ ///
+ /// Gets or sets the realm, or resource partition, associated with this System.Net.HttpListener
+ /// object.
+ ///
+ ///
+ /// A System.String value that contains the name of the realm associated with the
+ /// System.Net.HttpListener object.
+ ///
+ ///
+ /// This object has been closed.
+ ///
+ string Realm { get; set; }
+
+ ///
+ /// The timeout manager for this System.Net.HttpListener instance.
+ ///
+ ///
+ /// Returns System.Net.HttpListenerTimeoutManager.The timeout manager for this System.Net.HttpListener
+ /// instance.
+ ///
+ HttpListenerTimeoutManager TimeoutManager { get; }
+
+ ///
+ /// Gets or sets a System.Boolean value that controls whether, when NTLM is used,
+ /// additional requests using the same Transmission Control Protocol (TCP) connection
+ /// are required to authenticate.
+ ///
+ ///
+ /// true if the System.Security.Principal.IIdentity of the first request will be
+ /// used for subsequent requests on the same connection; otherwise, false. The default
+ /// value is false.
+ ///
+ ///
+ /// This object has been closed.
+ ///
+ bool UnsafeConnectionNtlmAuthentication { get; set; }
+
+ ///
+ /// Shuts down the System.Net.HttpListener object immediately, discarding all currently
+ /// queued requests.
+ ///
+ void Abort();
+
+ ///
+ /// Begins asynchronously retrieving an incoming request.
+ ///
+ ///
+ /// An System.AsyncCallback delegate that references the method to invoke when a
+ /// client request is available.
+ ///
+ ///
+ /// A user-defined object that contains information about the operation. This object
+ /// is passed to the callback delegate when the operation completes.
+ ///
+ ///
+ /// An System.IAsyncResult object that indicates the status of the asynchronous operation.
+ ///
+ ///
+ /// A Win32 function call failed. Check the exception's
+ /// property to determine the cause of the exception.
+ ///
+ ///
+ /// This object has not been started or is currently stopped.
+ ///
+ ///
+ /// This object has been closed.
+ ///
+ IAsyncResult BeginGetContext(AsyncCallback callback, object state);
+
+ ///
+ /// Shuts down the System.Net.HttpListener.
+ ///
+ void Close();
+
+ ///
+ /// Completes an asynchronous operation to retrieve an incoming client request.
+ ///
+ ///
+ /// An System.IAsyncResult object that was obtained when the asynchronous operation
+ /// was started.
+ ///
+ ///
+ /// An System.Net.HttpListenerContext object that represents the client request.
+ ///
+ ///
+ /// asyncResult was not obtained by calling the
+ ///
+ /// method.
+ ///
+ ///
+ /// asyncResult is null.
+ ///
+ ///
+ /// The System.Net.HttpListener.EndGetContext(System.IAsyncResult) method was already
+ /// called for the specified asyncResult object.
+ ///
+ ///
+ /// This object has been closed.
+ ///
+ IHttpListenerContext EndGetContext(IAsyncResult asyncResult);
+
+ ///
+ /// Waits for an incoming request and returns when one is received.
+ ///
+ ///
+ /// An System.Net.HttpListenerContext object that represents a client request.
+ ///
+ ///
+ /// A Win32 function call failed. Check the exception's
+ /// property to determine the cause of the exception.
+ ///
+ ///
+ /// This object has not been started or is currently stopped.-or-The System.Net.HttpListener
+ /// does not have any Uniform Resource Identifier (URI) prefixes to respond to. See
+ ///
+ ///
+ /// This object has been closed.
+ ///
+ IHttpListenerContext GetContext();
+
+ ///
+ /// Waits for an incoming request as an asynchronous operation.
+ ///
+ ///
+ /// Returns System.Threading.Tasks.Task`1.The task object representing the asynchronous
+ /// operation. The System.Threading.Tasks.Task`1.Result property on the task object
+ /// returns an System.Net.HttpListenerContext object that represents a client request.
+ ///
+ Task GetContextAsync();
+
+ ///
+ /// Allows this instance to receive incoming requests.
+ ///
+ ///
+ /// A Win32 function call failed. Check the exception's
+ /// property to determine the cause of the exception.
+ ///
+ ///
+ /// This object has been closed.
+ ///
+ void Start();
+
+ ///
+ /// Causes this instance to stop receiving incoming requests.
+ ///
+ ///
+ /// This object has been closed.
+ ///
+ void Stop();
+ }
+}
diff --git a/src/Net/IHttpListenerContext.cs b/src/Net/IHttpListenerContext.cs
new file mode 100644
index 0000000..824eb4c
--- /dev/null
+++ b/src/Net/IHttpListenerContext.cs
@@ -0,0 +1,158 @@
+using System;
+using System.ComponentModel;
+using System.Net.WebSockets;
+using System.Security.Principal;
+using System.Threading.Tasks;
+
+namespace Rothko
+{
+ ///
+ /// Provides access to the request and response objects used by the interface.
+ ///
+ public interface IHttpListenerContext
+ {
+ ///
+ /// Gets the that represents a client's request for
+ /// a resource.
+ ///
+ ///
+ /// An object that represents the client request.
+ ///
+ IHttpListenerRequest Request { get; }
+
+ ///
+ /// Gets the object that will be sent to the client
+ /// in response to the client's request.
+ ///
+ ///
+ /// An object used to send a response back to the client.
+ ///
+ IHttpListenerResponse Response { get; }
+
+ ///
+ /// Gets an object used to obtain identity, authentication information, and security
+ /// roles for the client whose request is represented by this System.Net.HttpListenerContext
+ /// object.
+ ///
+ ///
+ /// An object that describes the client, or null if the
+ /// that supplied this
+ /// does not require authentication.
+ ///
+ IPrincipal User { get; }
+
+ ///
+ /// Accept a WebSocket connection as an asynchronous operation.
+ ///
+ ///
+ /// The supported WebSocket sub-protocol.
+ ///
+ ///
+ /// Returns System.Threading.Tasks.Task`1.The task object representing the asynchronous
+ /// operation. The System.Threading.Tasks.Task`1.Result property on the task object
+ /// returns an System.Net.WebSockets.HttpListenerWebSocketContext object.
+ ///
+ ///
+ /// is an empty string-or-
+ /// contains illegal characters.
+ ///
+ ///
+ /// An error occurred when sending the response to complete the WebSocket handshake.
+ ///
+ Task AcceptWebSocketAsync(string subProtocol);
+
+ ///
+ /// Accept a WebSocket connection specifying the supported WebSocket sub-protocol
+ /// and WebSocket keep-alive interval as an asynchronous operation.
+ ///
+ ///
+ /// The supported WebSocket sub-protocol.
+ ///
+ ///
+ /// The WebSocket protocol keep-alive interval in milliseconds.
+ ///
+ ///
+ /// Returns System.Threading.Tasks.Task`1.The task object representing the asynchronous
+ /// operation. The System.Threading.Tasks.Task`1.Result property on the task object
+ /// returns an System.Net.WebSockets.HttpListenerWebSocketContext object.
+ ///
+ ///
+ /// is an empty string-or-
+ /// contains illegal characters.
+ ///
+ ///
+ /// is too small.
+ ///
+ ///
+ /// An error occurred when sending the response to complete the WebSocket handshake.
+ ///
+ Task AcceptWebSocketAsync(string subProtocol, TimeSpan keepAliveInterval);
+
+ ///
+ /// Accept a WebSocket connection specifying the supported WebSocket sub-protocol,
+ /// receive buffer size, and WebSocket keep-alive interval as an asynchronous operation.
+ ///
+ ///
+ /// The supported WebSocket sub-protocol.
+ ///
+ ///
+ /// The receive buffer size in bytes.
+ ///
+ ///
+ /// The WebSocket protocol keep-alive interval in milliseconds.
+ ///
+ ///
+ /// Returns System.Threading.Tasks.Task`1.The task object representing the asynchronous
+ /// operation. The System.Threading.Tasks.Task`1.Result property on the task object
+ /// returns an System.Net.WebSockets.HttpListenerWebSocketContext object.
+ ///
+ ///
+ /// is an empty string-or-
+ /// contains illegal characters.
+ ///
+ ///
+ /// is too small.-or- receiveBufferSize is less than 16 bytes-or-
+ /// is greater than 64K bytes.
+ ///
+ ///
+ /// An error occurred when sending the response to complete the WebSocket handshake.
+ ///
+ Task AcceptWebSocketAsync(string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval);
+
+ ///
+ /// Accept a WebSocket connection specifying the supported WebSocket sub-protocol,
+ /// receive buffer size, WebSocket keep-alive interval, and the internal buffer as
+ /// an asynchronous operation.
+ ///
+ ///
+ /// The supported WebSocket sub-protocol.
+ ///
+ ///
+ /// The receive buffer size in bytes.
+ ///
+ ///
+ /// The WebSocket protocol keep-alive interval in milliseconds.
+ ///
+ ///
+ /// An internal buffer to use for this operation.
+ ///
+ ///
+ /// Returns System.Threading.Tasks.Task`1.The task object representing the asynchronous
+ /// operation. The System.Threading.Tasks.Task`1.Result property on the task object
+ /// returns an System.Net.WebSockets.HttpListenerWebSocketContext object.
+ ///
+ ///
+ /// is an empty string-or-
+ /// contains illegal characters.
+ ///
+ ///
+ /// is too small.-or- receiveBufferSize is less than 16 bytes-or-
+ /// is greater than 64K bytes.
+ ///
+ ///
+ /// An error occurred when sending the response to complete the WebSocket handshake.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ Task AcceptWebSocketAsync(string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval, ArraySegment internalBuffer);
+ }
+}
diff --git a/src/Net/IHttpListenerRequest.cs b/src/Net/IHttpListenerRequest.cs
new file mode 100644
index 0000000..bbd772f
--- /dev/null
+++ b/src/Net/IHttpListenerRequest.cs
@@ -0,0 +1,334 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.IO;
+using System.Net;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Rothko
+{
+ ///
+ /// Describes an incoming HTTP request to an System.Net.HttpListener object.
+ ///
+ public interface IHttpListenerRequest
+ {
+ ///
+ /// Gets the MIME types accepted by the client.
+ ///
+ ///
+ /// A array that contains the type names specified in the request's
+ /// Accept header or null if the client request did not include an Accept header.
+ ///
+ IEnumerable AcceptTypes { get; }
+
+ ///
+ /// Gets an error code that identifies a problem with the
+ /// provided by the client.
+ ///
+ ///
+ /// An System.Int32 value that contains a Windows error code.
+ ///
+ ///
+ /// The client certificate has not been initialized yet by a call to the
+ /// or methods -or - The operation
+ /// is still in progress.
+ ///
+ int ClientCertificateError { get; }
+
+ ///
+ /// Gets the content encoding that can be used with data sent with the request
+ ///
+ ///
+ /// An object suitable for use with the data in the
+ /// property.
+ ///
+ Encoding ContentEncoding { get; }
+
+ ///
+ /// Gets the length of the body data included in the request.
+ ///
+ ///
+ /// The value from the request's Content-Length header. This value is -1 if the content
+ /// length is not known.
+ ///
+ long ContentLength64 { get; }
+
+ ///
+ /// Gets the MIME type of the body data included in the request.
+ ///
+ ///
+ /// A that contains the text of the request's Content-Type header.
+ ///
+ string ContentType { get; }
+
+ ///
+ /// Gets the cookies sent with the request.
+ ///
+ ///
+ /// A that contains cookies that accompany the request.
+ /// This property returns an empty collection if the request does not contain cookies.
+ ///
+ CookieCollection Cookies { get; }
+
+ ///
+ /// Gets a value that indicates whether the request has associated
+ /// body data.
+ ///
+ ///
+ /// true if the request has associated body data; otherwise, false.
+ ///
+ bool HasEntityBody { get; }
+
+ ///
+ /// Gets the collection of header name/value pairs sent in the request.
+ ///
+ ///
+ /// A that contains the HTTP headers included in the
+ /// request.
+ ///
+ NameValueCollection Headers { get; }
+
+ ///
+ /// Gets the HTTP method specified by the client.
+ ///
+ ///
+ /// A that contains the method used in the request.
+ ///
+ string HttpMethod { get; }
+
+ ///
+ /// Gets a stream that contains the body data sent by the client.
+ ///
+ ///
+ /// A readable object that contains the bytes sent by the client
+ /// in the body of the request. This property returns if no
+ /// data is sent with the request.
+ ///
+ Stream InputStream { get; }
+
+ ///
+ /// Gets a value that indicates whether the client sending this request
+ /// is authenticated.
+ ///
+ ///
+ /// true if the client was authenticated; otherwise, false.
+ ///
+ bool IsAuthenticated { get; }
+
+ ///
+ /// Gets a value that indicates whether the request is sent from the
+ /// local computer.
+ ///
+ ///
+ /// true if the request originated on the same computer as the
+ /// object that provided the request; otherwise, false.
+ ///
+ bool IsLocal { get; }
+
+ ///
+ /// Gets a value that indicates whether the TCP connection used to
+ /// send the request is using the Secure Sockets Layer (SSL) protocol.
+ ///
+ ///
+ /// true if the TCP connection is using SSL; otherwise, false.
+ ///
+ bool IsSecureConnection { get; }
+
+ ///
+ /// Gets a value that indicates whether the TCP connection was a WebSocket
+ /// request.
+ ///
+ ///
+ /// Returns true if the TCP connection is a WebSocket request; otherwise, false.
+ ///
+ bool IsWebSocketRequest { get; }
+
+ ///
+ /// Gets a value that indicates whether the client requests a persistent
+ /// connection.
+ ///
+ ///
+ /// true if the connection should be kept open; otherwise, false.
+ ///
+ bool KeepAlive { get; }
+
+ ///
+ /// Get the server IP address and port number to which the request is directed.
+ ///
+ ///
+ /// An that represents the IP address that the request is sent
+ /// to.
+ ///
+ IPEndPoint LocalEndPoint { get; }
+
+ ///
+ /// Gets the HTTP version used by the requesting client.
+ ///
+ ///
+ /// A that identifies the client's version of HTTP.
+ ///
+ Version ProtocolVersion { get; }
+
+ ///
+ /// Gets the query string included in the request.
+ ///
+ ///
+ /// A object that contains the query data included in
+ /// the request .
+ ///
+ NameValueCollection QueryString { get; }
+
+ ///
+ /// Gets the URL information (without the host and port) requested by the client.
+ ///
+ ///
+ /// A that contains the raw URL for this request.
+ ///
+ string RawUrl { get; }
+
+ ///
+ /// Gets the client IP address and port number from which the request originated.
+ ///
+ ///
+ /// An that represents the IP address and port number from
+ /// which the request originated.
+ ///
+ IPEndPoint RemoteEndPoint { get; }
+
+ ///
+ /// Gets the request identifier of the incoming HTTP request.
+ ///
+ ///
+ /// A object that contains the identifier of the HTTP request.
+ ///
+ Guid RequestTraceIdentifier { get; }
+
+ ///
+ /// Gets the Service Provider Name (SPN) that the client sent on the request.
+ ///
+ ///
+ /// A that contains the SPN the client sent on the request.
+ ///
+ string ServiceName { get; }
+
+ ///
+ /// Gets the for the client request.
+ ///
+ ///
+ /// A object for the client request.
+ ///
+ TransportContext TransportContext { get; }
+
+ ///
+ /// Gets the object requested by the client.
+ ///
+ ///
+ /// A object that identifies the resource requested by the client.
+ ///
+ Uri Url { get; }
+
+ ///
+ /// Gets the Uniform Resource Identifier (URI) of the resource that referred the
+ /// client to the server.
+ ///
+ ///
+ /// A object that contains the text of the request's
+ /// header, or null if the header was not included in the request.
+ ///
+ Uri UrlReferrer { get; }
+
+ ///
+ /// Gets the user agent presented by the client.
+ ///
+ ///
+ /// A object that contains the text of the request's User-Agent header.
+ ///
+ string UserAgent { get; }
+
+ ///
+ /// Gets the server IP address and port number to which the request is directed.
+ ///
+ ///
+ /// A that contains the host address information.
+ ///
+ string UserHostAddress { get; }
+
+ ///
+ /// Gets the DNS name and, if provided, the port number specified by the client.
+ ///
+ ///
+ /// A value that contains the text of the request's Host header.
+ ///
+ string UserHostName { get; }
+
+ ///
+ /// Gets the natural languages that are preferred for the response.
+ ///
+ ///
+ /// A array that contains the languages specified in the request's
+ /// header or null if the client request
+ /// did not include an header.
+ ///
+ IEnumerable UserLanguages { get; }
+
+ ///
+ /// Begins an asynchronous request for the client's X.509 v.3 certificate.
+ ///
+ ///
+ /// An delegate that references the method to invoke when the
+ /// operation is complete.
+ ///
+ ///
+ /// A user-defined object that contains information about the operation. This object
+ /// is passed to the callback delegate when the operation completes.
+ ///
+ ///
+ /// An that indicates the status of the operation.
+ ///
+ IAsyncResult BeginGetClientCertificate(AsyncCallback requestCallback, object state);
+
+ ///
+ /// Ends an asynchronous request for the client's X.509 v.3 certificate.
+ ///
+ ///
+ /// The pending request for the certificate.
+ ///
+ ///
+ /// The System.IAsyncResult object that is returned when the operation started.
+ ///
+ ///
+ /// asyncResult is null.
+ ///
+ ///
+ /// asyncResult was not obtained by calling .
+ ///
+ ///
+ /// This method was already called for the operation identified by asyncResult.
+ ///
+ X509Certificate2 EndGetClientCertificate(IAsyncResult asyncResult);
+
+ ///
+ /// Retrieves the client's X.509 v.3 certificate.
+ ///
+ ///
+ /// A object that contains the client's X.509 v.3 certificate.
+ ///
+ ///
+ /// A call to this method to retrieve the client's X.509 v.3 certificate is in progress
+ /// and therefore another call to this method cannot be made.
+ ///
+ X509Certificate2 GetClientCertificate();
+
+ ///
+ /// Retrieves the client's X.509 v.3 certificate as an asynchronous operation.
+ ///
+ ///
+ /// The task object representing the asynchronous operation. The property
+ /// on the task object returns a object that containsthe client's X.509 v.3
+ /// certificate.
+ ///
+ Task GetClientCertificateAsync();
+ }
+}
diff --git a/src/Net/IHttpListenerResponse.cs b/src/Net/IHttpListenerResponse.cs
new file mode 100644
index 0000000..54049be
--- /dev/null
+++ b/src/Net/IHttpListenerResponse.cs
@@ -0,0 +1,300 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Text;
+
+namespace Rothko
+{
+ ///
+ /// Represents a response to a request being handled by an .
+ ///
+ public interface IHttpListenerResponse : IDisposable
+ {
+ ///
+ /// Gets or sets the for this response's .
+ ///
+ ///
+ /// An object suitable for use with the data in the
+ /// property, or null if no encoding is specified.
+ ///
+ Encoding ContentEncoding { get; set; }
+
+ ///
+ /// Gets or sets the number of bytes in the body data included in the response.
+ ///
+ ///
+ /// The value of the response's Content-Length header.
+ ///
+ ///
+ /// The value specified for a set operation is less than zero.
+ ///
+ ///
+ /// The response is already being sent.
+ ///
+ ///
+ /// This object is closed.
+ ///
+ long ContentLength64 { get; set; }
+
+ ///
+ /// Gets or sets the MIME type of the content returned.
+ ///
+ ///
+ /// A instance that contains the text of the response's Content-Type
+ /// header.
+ ///
+ ///
+ /// The value specified for a set operation is null.
+ ///
+ ///
+ /// The value specified for a set operation is an empty string ("").
+ ///
+ ///
+ /// This object is closed.
+ ///
+ string ContentType { get; set; }
+
+ ///
+ /// Gets or sets the collection of cookies returned with the response.
+ ///
+ ///
+ /// A that contains cookies to accompany the response.
+ /// The collection is empty if no cookies have been added to the response.
+ ///
+ CookieCollection Cookies { get; set; }
+
+ ///
+ /// Gets or sets the collection of header name/value pairs returned by the server.
+ ///
+ ///
+ /// A instance that contains all the explicitly set
+ /// HTTP headers to be included in the response.
+ ///
+ ///
+ /// The instance specified for a set operation is
+ /// not valid for a response.
+ ///
+ WebHeaderCollection Headers { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the server requests a persistent connection.
+ ///
+ ///
+ /// true if the server requests a persistent connection; otherwise, false. The default
+ /// is true.
+ ///
+ ///
+ /// This object is closed.
+ ///
+ bool KeepAlive { get; set; }
+
+ ///
+ /// Gets a System.IO.Stream object to which a response can be written.
+ ///
+ ///
+ /// A System.IO.Stream object to which a response can be written.
+ ///
+ ///
+ /// This object is closed.
+ ///
+ Stream OutputStream { get; }
+
+ ///
+ /// Gets or sets the HTTP version used for the response.
+ ///
+ ///
+ /// A object indicating the version of HTTP used when responding to
+ /// the client. Note that this property is now obsolete.
+ ///
+ ///
+ /// The value specified for a set operation is null.
+ ///
+ ///
+ /// The value specified for a set operation does not have its
+ /// property set to 1 or does not have its property set to either
+ /// 0 or 1.
+ ///
+ ///
+ /// This object is closed.
+ ///
+ Version ProtocolVersion { get; set; }
+
+ ///
+ /// Gets or sets the value of the HTTP Location header in this response.
+ ///
+ ///
+ /// A that contains the absolute URL to be sent to the client in the
+ /// Location header.
+ ///
+ ///
+ /// The value specified for a set operation is an empty string ("").
+ ///
+ ///
+ /// This object is closed.
+ ///
+ string RedirectLocation { get; set; }
+
+ ///
+ /// Gets or sets whether the response uses chunked transfer encoding.
+ ///
+ ///
+ /// true if the response is set to use chunked transfer encoding; otherwise, false.
+ /// The default is false.
+ ///
+ bool SendChunked { get; set; }
+
+ ///
+ /// Gets or sets the HTTP status code to be returned to the client.
+ ///
+ ///
+ /// An value that specifies the HTTP status code for the requested resource.
+ /// The default is , indicating that the server successfully
+ /// processed the client's request and included the requested resource in the response
+ /// body.
+ ///
+ ///
+ /// This object is closed.
+ ///
+ ///
+ /// The value specified for a set operation is not valid. Valid values are between
+ /// 100 and 999 inclusive.
+ ///
+ int StatusCode { get; set; }
+
+ ///
+ /// Gets or sets a text description of the HTTP status code returned to the client.
+ ///
+ ///
+ /// The text description of the HTTP status code returned to the client. The default
+ /// is the RFC 2616 description for the System.Net.HttpListenerResponse.StatusCode
+ /// property value, or an empty string ("") if an RFC 2616 description does not exist.
+ ///
+ /// Exceptions:
+ ///
+ /// The value specified for a set operation is null.
+ ///
+ ///
+ /// The value specified for a set operation contains non-printable characters.
+ ///
+ string StatusDescription { get; set; }
+
+ ///
+ /// Closes the connection to the client without sending a response.
+ ///
+ void Abort();
+
+ ///
+ /// Adds the specified header and value to the HTTP headers for this response.
+ ///
+ ///
+ /// The name of the HTTP header to set.
+ ///
+ ///
+ /// The value for the name header.
+ ///
+ ///
+ /// name is null or an empty string ("").
+ ///
+ ///
+ /// You are not allowed to specify a value for the specified header.-or-name or value
+ /// contains invalid characters.
+ ///
+ ///
+ /// The length of value is greater than 65,535 characters.
+ ///
+ void AddHeader(string name, string value);
+
+ ///
+ /// Adds the specified System.Net.Cookie to the collection of cookies for this response.
+ ///
+ ///
+ /// The System.Net.Cookie to add to the collection to be sent with this response
+ ///
+ ///
+ /// cookie is null.
+ ///
+ void AppendCookie(Cookie cookie);
+
+ ///
+ /// Appends a value to the specified HTTP header to be sent with this response.
+ ///
+ ///
+ /// The name of the HTTP header to append value to.
+ ///
+ ///
+ /// The value to append to the name header.
+ ///
+ ///
+ /// name is null or an empty string ("").-or-You are not allowed to specify a value
+ /// for the specified header.-or-name or value contains invalid characters.
+ ///
+ ///
+ /// The length of value is greater than 65,535 characters.
+ ///
+ void AppendHeader(string name, string value);
+
+ ///
+ /// Sends the response to the client and releases the resources held by this System.Net.HttpListenerResponse
+ /// instance.
+ ///
+ void Close();
+
+ ///
+ /// Returns the specified byte array to the client and releases the resources held
+ /// by this System.Net.HttpListenerResponse instance.
+ ///
+ ///
+ /// A array that contains the response to send to the client.
+ ///
+ ///
+ /// true to block execution while flushing the stream to the client; otherwise, false.
+ ///
+ ///
+ /// responseEntity is null.
+ ///
+ ///
+ /// This object is closed.
+ ///
+ void Close(byte[] responseEntity, bool willBlock);
+
+ ///
+ /// Copies properties from the specified System.Net.HttpListenerResponse to this
+ /// response.
+ ///
+ ///
+ /// The System.Net.HttpListenerResponse instance to copy.
+ ///
+ void CopyFrom(HttpListenerResponse templateResponse);
+
+ ///
+ /// Configures the response to redirect the client to the specified URL.
+ ///
+ ///
+ /// The URL that the client should use to locate the requested resource.
+ ///
+ void Redirect(string url);
+
+ ///
+ /// Configures the response to redirect the client to the specified URL.
+ ///
+ ///
+ /// The URL that the client should use to locate the requested resource.
+ ///
+ void Redirect(Uri url);
+
+ ///
+ /// Adds or updates a System.Net.Cookie in the collection of cookies sent with this
+ /// response.
+ ///
+ ///
+ /// A for this response.
+ ///
+ ///
+ /// cookie is null.
+ ///
+ ///
+ /// The cookie already exists in the collection and could not be replaced.
+ ///
+ void SetCookie(Cookie cookie);
+ }
+}
diff --git a/src/Net/INetFactory.cs b/src/Net/INetFactory.cs
new file mode 100644
index 0000000..7a31a02
--- /dev/null
+++ b/src/Net/INetFactory.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Rothko
+{
+ public interface INetFactory
+ {
+ IHttpListener CreateHttpListener();
+ }
+}
diff --git a/src/Net/NetFactory.cs b/src/Net/NetFactory.cs
new file mode 100644
index 0000000..af3bf89
--- /dev/null
+++ b/src/Net/NetFactory.cs
@@ -0,0 +1,12 @@
+using System.Net;
+
+namespace Rothko
+{
+ public class NetFactory : INetFactory
+ {
+ public IHttpListener CreateHttpListener()
+ {
+ return new HttpListenerWrapper(new HttpListener());
+ }
+ }
+}
diff --git a/src/Networking/HttpClient.cs b/src/Networking/HttpClient.cs
new file mode 100644
index 0000000..60dec03
--- /dev/null
+++ b/src/Networking/HttpClient.cs
@@ -0,0 +1,253 @@
+using System;
+using System.IO;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Rothko
+{
+ ///
+ /// Provides a base class for sending HTTP requests and receiving HTTP responses from a resource identified by a URI.
+ ///
+ public class HttpClient : IHttpClient
+ {
+ private readonly System.Net.Http.HttpClient innerHttpClient;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public HttpClient()
+ : this(new System.Net.Http.HttpClient())
+ {
+
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specific handler.
+ ///
+ /// The HTTP handler stack to use for sending requests.
+ public HttpClient(HttpMessageHandler handler)
+ : this(new System.Net.Http.HttpClient(handler))
+ {
+
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specific handler.
+ ///
+ /// The responsible for processing the HTTP response messages.
+ /// true if the inner handler should be disposed of by Dispose(),false if you intend to reuse the inner handler.
+ public HttpClient(HttpMessageHandler handler, bool disposeHandler)
+ : this(new System.Net.Http.HttpClient(handler, disposeHandler))
+ {
+
+ }
+
+ protected HttpClient(System.Net.Http.HttpClient httpClient)
+ {
+ Guard.NotNull(httpClient, "httpClient");
+
+ innerHttpClient = httpClient;
+ }
+
+ public Task GetStringAsync(string requestUri)
+ {
+ return innerHttpClient.GetStringAsync(requestUri);
+ }
+
+ public Task GetStringAsync(Uri requestUri)
+ {
+ return innerHttpClient.GetStringAsync(requestUri);
+ }
+
+ public Task GetByteArrayAsync(string requestUri)
+ {
+ return innerHttpClient.GetByteArrayAsync(requestUri);
+ }
+
+ public Task GetByteArrayAsync(Uri requestUri)
+ {
+ return innerHttpClient.GetByteArrayAsync(requestUri);
+ }
+
+ public Task GetStreamAsync(string requestUri)
+ {
+ return innerHttpClient.GetStreamAsync(requestUri);
+ }
+
+ public Task GetStreamAsync(Uri requestUri)
+ {
+ return innerHttpClient.GetStreamAsync(requestUri);
+ }
+
+ public Task GetAsync(string requestUri)
+ {
+ return innerHttpClient.GetAsync(requestUri);
+ }
+
+ public Task GetAsync(Uri requestUri)
+ {
+ return innerHttpClient.GetAsync(requestUri);
+ }
+
+ public Task GetAsync(string requestUri, HttpCompletionOption completionOption)
+ {
+ return innerHttpClient.GetAsync(requestUri, completionOption);
+ }
+
+ public Task GetAsync(Uri requestUri, HttpCompletionOption completionOption)
+ {
+ return innerHttpClient.GetAsync(requestUri, completionOption);
+ }
+
+ public Task GetAsync(string requestUri, CancellationToken cancellationToken)
+ {
+ return innerHttpClient.GetAsync(requestUri, cancellationToken);
+ }
+
+ public Task GetAsync(Uri requestUri, CancellationToken cancellationToken)
+ {
+ return innerHttpClient.GetAsync(requestUri, cancellationToken);
+ }
+
+ public Task GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken)
+ {
+ return innerHttpClient.GetAsync(requestUri, completionOption, cancellationToken);
+ }
+
+ public Task GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken)
+ {
+ return innerHttpClient.GetAsync(requestUri, completionOption, cancellationToken);
+ }
+
+ public Task PostAsync(string requestUri, HttpContent content)
+ {
+ return innerHttpClient.PostAsync(requestUri, content);
+ }
+
+ public Task PostAsync(Uri requestUri, HttpContent content)
+ {
+ return innerHttpClient.PostAsync(requestUri, content);
+ }
+
+ public Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken)
+ {
+ return innerHttpClient.PostAsync(requestUri, content, cancellationToken);
+ }
+
+ public Task PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken)
+ {
+ return innerHttpClient.PostAsync(requestUri, content, cancellationToken);
+ }
+
+ public Task PutAsync(string requestUri, HttpContent content)
+ {
+ return innerHttpClient.PutAsync(requestUri, content);
+ }
+
+ public Task PutAsync(Uri requestUri, HttpContent content)
+ {
+ return innerHttpClient.PutAsync(requestUri, content);
+ }
+
+ public Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken)
+ {
+ return innerHttpClient.PutAsync(requestUri, content, cancellationToken);
+ }
+
+ public Task PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken)
+ {
+ return innerHttpClient.PutAsync(requestUri, content, cancellationToken);
+ }
+
+ public Task DeleteAsync(string requestUri)
+ {
+ return innerHttpClient.DeleteAsync(requestUri);
+ }
+
+ public Task DeleteAsync(Uri requestUri)
+ {
+ return innerHttpClient.DeleteAsync(requestUri);
+ }
+
+ public Task DeleteAsync(string requestUri, CancellationToken cancellationToken)
+ {
+ return innerHttpClient.DeleteAsync(requestUri, cancellationToken);
+ }
+
+ public Task DeleteAsync(Uri requestUri, CancellationToken cancellationToken)
+ {
+ return innerHttpClient.DeleteAsync(requestUri, cancellationToken);
+ }
+
+ public Task SendAsync(HttpRequestMessage request)
+ {
+ return innerHttpClient.SendAsync(request);
+ }
+
+ public Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ return innerHttpClient.SendAsync(request, cancellationToken);
+ }
+
+ public Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption)
+ {
+ return innerHttpClient.SendAsync(request, completionOption);
+ }
+
+ public Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
+ {
+ return innerHttpClient.SendAsync(request, completionOption, cancellationToken);
+ }
+
+ public void CancelPendingRequests()
+ {
+ innerHttpClient.CancelPendingRequests();
+ }
+
+ public HttpRequestHeaders DefaultRequestHeaders
+ {
+ get { return innerHttpClient.DefaultRequestHeaders; }
+ }
+
+ public Uri BaseAddress
+ {
+ get { return innerHttpClient.BaseAddress; }
+ set { innerHttpClient.BaseAddress = value; }
+ }
+
+ public TimeSpan Timeout
+ {
+ get { return innerHttpClient.Timeout; }
+ set { innerHttpClient.Timeout = value; }
+ }
+
+ public long MaxResponseContentBufferSize
+ {
+ get { return innerHttpClient.MaxResponseContentBufferSize; }
+ set { innerHttpClient.MaxResponseContentBufferSize = value; }
+ }
+
+ ///
+ /// Releases the unmanaged resources used by the and optionally disposes of the managed resources.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ System.Net.Http.HttpClient httpClient = innerHttpClient;
+ if (httpClient != null)
+ {
+ httpClient.Dispose();
+ }
+ }
+ }
+ }
+}
diff --git a/src/Networking/IHttpClient.cs b/src/Networking/IHttpClient.cs
new file mode 100644
index 0000000..468e914
--- /dev/null
+++ b/src/Networking/IHttpClient.cs
@@ -0,0 +1,359 @@
+using System;
+using System.IO;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Runtime;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Rothko
+{
+ public interface IHttpClient : IDisposable
+ {
+ ///
+ /// Send a GET request to the specified Uri and return the response body as a string in an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The was null.
+ Task GetStringAsync(string requestUri);
+
+ ///
+ /// Send a GET request to the specified Uri and return the response body as a string in an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The was null.
+ Task GetStringAsync(Uri requestUri);
+
+ ///
+ /// Send a GET request to the specified Uri and return the response body as a byte array in an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The was null.
+ Task GetByteArrayAsync(string requestUri);
+
+ ///
+ /// Send a GET request to the specified Uri and return the response body as a byte array in an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The was null.
+ Task GetByteArrayAsync(Uri requestUri);
+
+ ///
+ /// Send a GET request to the specified Uri and return the response body as a stream in an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The was null.
+ Task GetStreamAsync(string requestUri);
+
+ ///
+ /// Send a GET request to the specified Uri and return the response body as a stream in an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The was null.
+ Task GetStreamAsync(Uri requestUri);
+
+ ///
+ /// Send a GET request to the specified Uri as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The was null.
+ Task GetAsync(string requestUri);
+
+ ///
+ /// Send a GET request to the specified Uri as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The was null.
+ [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
+ Task GetAsync(Uri requestUri);
+
+ ///
+ /// Send a GET request to the specified Uri with an HTTP completion option as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .
+ ///
+ /// The Uri the request is sent to.An HTTP completion option value that indicates when the operation should be considered completed.The was null.
+ Task GetAsync(string requestUri, HttpCompletionOption completionOption);
+
+ ///
+ /// Send a GET request to the specified Uri with an HTTP completion option as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.An HTTP completion option value that indicates when the operation should be considered completed.The was null.
+ Task GetAsync(Uri requestUri, HttpCompletionOption completionOption);
+
+ ///
+ /// Send a GET request to the specified Uri with a cancellation token as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .
+ ///
+ /// The Uri the request is sent to.A cancellation token that can be used by other objects or threads to receive notice of cancellation.The was null.
+ Task GetAsync(string requestUri, CancellationToken cancellationToken);
+
+ ///
+ /// Send a GET request to the specified Uri with a cancellation token as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.A cancellation token that can be used by other objects or threads to receive notice of cancellation.The was null.
+ [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
+ Task GetAsync(Uri requestUri, CancellationToken cancellationToken);
+
+ ///
+ /// Send a GET request to the specified Uri with an HTTP completion option and a cancellation token as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .
+ ///
+ /// The Uri the request is sent to.An HTTP completion option value that indicates when the operation should be considered completed.A cancellation token that can be used by other objects or threads to receive notice of cancellation.The was null.
+ Task GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken);
+
+ ///
+ /// Send a GET request to the specified Uri with an HTTP completion option and a cancellation token as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.An HTTP completion option value that indicates when the operation should be considered completed.A cancellation token that can be used by other objects or threads to receive notice of cancellation.The was null.
+ Task GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken);
+
+ ///
+ /// Send a POST request to the specified Uri as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The HTTP request content sent to the server.The was null.
+ Task PostAsync(string requestUri, HttpContent content);
+
+ ///
+ /// Send a POST request to the specified Uri as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The HTTP request content sent to the server.The was null.
+ Task PostAsync(Uri requestUri, HttpContent content);
+
+ ///
+ /// Send a POST request with a cancellation token as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The HTTP request content sent to the server.A cancellation token that can be used by other objects or threads to receive notice of cancellation.The was null.
+ Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken);
+
+ ///
+ /// Send a POST request with a cancellation token as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The HTTP request content sent to the server.A cancellation token that can be used by other objects or threads to receive notice of cancellation.The was null.
+ Task PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken);
+
+ ///
+ /// Send a PUT request to the specified Uri as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The HTTP request content sent to the server.The was null.
+ Task PutAsync(string requestUri, HttpContent content);
+
+ ///
+ /// Send a PUT request to the specified Uri as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The HTTP request content sent to the server.The was null.
+ Task PutAsync(Uri requestUri, HttpContent content);
+
+ ///
+ /// Send a PUT request with a cancellation token as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The HTTP request content sent to the server.A cancellation token that can be used by other objects or threads to receive notice of cancellation.The was null.
+ Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken);
+
+ ///
+ /// Send a PUT request with a cancellation token as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The HTTP request content sent to the server.A cancellation token that can be used by other objects or threads to receive notice of cancellation.The was null.
+ Task PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken);
+
+ ///
+ /// Send a DELETE request to the specified Uri as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The was null.The request message was already sent by the instance.
+ Task DeleteAsync(string requestUri);
+
+ ///
+ /// Send a DELETE request to the specified Uri as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.The was null.The request message was already sent by the instance.
+ Task DeleteAsync(Uri requestUri);
+
+ ///
+ /// Send a DELETE request to the specified Uri with a cancellation token as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.A cancellation token that can be used by other objects or threads to receive notice of cancellation.The was null.The request message was already sent by the instance.
+ Task DeleteAsync(string requestUri, CancellationToken cancellationToken);
+
+ ///
+ /// Send a DELETE request to the specified Uri with a cancellation token as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The Uri the request is sent to.A cancellation token that can be used by other objects or threads to receive notice of cancellation.The was null.The request message was already sent by the instance.
+ Task DeleteAsync(Uri requestUri, CancellationToken cancellationToken);
+
+ ///
+ /// Send an HTTP request as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The HTTP request message to send.The was null.The request message was already sent by the instance.
+ Task SendAsync(HttpRequestMessage request);
+
+ ///
+ /// Send an HTTP request as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The HTTP request message to send.The cancellation token to cancel operation.The was null.The request message was already sent by the instance.
+ [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
+ Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
+
+ ///
+ /// Send an HTTP request as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The HTTP request message to send.When the operation should complete (as soon as a response is available or after reading the whole response content).The was null.The request message was already sent by the instance.
+ Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption);
+
+ ///
+ /// Send an HTTP request as an asynchronous operation.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation.
+ ///
+ /// The HTTP request message to send.When the operation should complete (as soon as a response is available or after reading the whole response content).The cancellation token to cancel operation.The was null.The request message was already sent by the instance.
+ Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken);
+
+ ///
+ /// Cancel all pending requests on this instance.
+ ///
+ void CancelPendingRequests();
+
+ ///
+ /// Gets the headers which should be sent with each request.
+ ///
+ ///
+ ///
+ /// Returns .The headers which should be sent with each request.
+ ///
+ HttpRequestHeaders DefaultRequestHeaders { get; }
+
+ ///
+ /// Gets or sets the base address of Uniform Resource Identifier (URI) of the Internet resource used when sending requests.
+ ///
+ ///
+ ///
+ /// Returns .The base address of Uniform Resource Identifier (URI) of the Internet resource used when sending requests.
+ ///
+ Uri BaseAddress { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; set; }
+
+ ///
+ /// Gets or sets the number of milliseconds to wait before the request times out.
+ ///
+ ///
+ ///
+ /// Returns .The number of milliseconds to wait before the request times out.
+ ///
+ /// The timeout specified is less than or equal to zero and is not .An operation has already been started on the current instance. The current instance has been disposed.
+ TimeSpan Timeout { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; set; }
+
+ ///
+ /// Gets or sets the maximum number of bytes to buffer when reading the response content.
+ ///
+ ///
+ ///
+ /// Returns .The maximum number of bytes to buffer when reading the response content. The default value for this property is 2 gigabytes.
+ ///
+ /// The size specified is less than or equal to zero.An operation has already been started on the current instance. The current instance has been disposed.
+ long MaxResponseContentBufferSize { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Networking/IWebClient.cs b/src/Networking/IWebClient.cs
new file mode 100644
index 0000000..5c60c2e
--- /dev/null
+++ b/src/Networking/IWebClient.cs
@@ -0,0 +1,401 @@
+using System;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Net;
+using System.Net.Cache;
+
+namespace Rothko
+{
+ public interface IWebClient : IDisposable
+ {
+ byte[] DownloadData(string address);
+
+ ///
+ /// Downloads the resource as a array from the URI specified.
+ ///
+ ///
+ ///
+ /// A array containing the downloaded resource.
+ ///
+ /// The URI represented by the object, from which to download data.
+ /// The parameter is null.
+ byte[] DownloadData(Uri address);
+
+ void DownloadFile(string address, string fileName);
+ void DownloadFile(Uri address, string fileName);
+ System.IO.Stream OpenRead(string address);
+
+ ///
+ /// Opens a readable stream for the data downloaded from a resource with the URI specified as a
+ ///
+ ///
+ ///
+ /// A used to read data from a resource.
+ ///
+ /// The URI specified as a from which to download data.
+ /// The parameter is null.
+ /// The URI formed by combining , is invalid.-or- An error occurred while downloading data.
+ System.IO.Stream OpenRead(Uri address);
+
+ System.IO.Stream OpenWrite(string address);
+
+ ///
+ /// Opens a stream for writing data to the specified resource.
+ ///
+ ///
+ ///
+ /// A used to write data to the resource.
+ ///
+ /// The URI of the resource to receive the data.
+ /// The parameter is null.
+ /// The URI formed by combining , and is invalid.-or- An error occurred while opening the stream.
+ System.IO.Stream OpenWrite(Uri address);
+
+ System.IO.Stream OpenWrite(string address, string method);
+ System.IO.Stream OpenWrite(Uri address, string method);
+ byte[] UploadData(string address, byte[] data);
+ byte[] UploadData(Uri address, byte[] data);
+ byte[] UploadData(string address, string method, byte[] data);
+ byte[] UploadData(Uri address, string method, byte[] data);
+ byte[] UploadFile(string address, string fileName);
+ byte[] UploadFile(Uri address, string fileName);
+ byte[] UploadFile(string address, string method, string fileName);
+ byte[] UploadFile(Uri address, string method, string fileName);
+ byte[] UploadValues(string address, NameValueCollection data);
+
+ ///
+ /// Uploads the specified name/value collection to the resource identified by the specified URI.
+ ///
+ ///
+ ///
+ /// A array containing the body of the response from the resource.
+ ///
+ /// The URI of the resource to receive the collection.
+ /// The to send to the resource.
+ /// The parameter is null.-or-The parameter is null.
+ /// The URI formed by combining , and is invalid.-or- is null.-or- There was no response from the server hosting the resource.-or- An error occurred while opening the stream.-or- The Content-type header is not null or "application/x-www-form-urlencoded".
+ byte[] UploadValues(Uri address, NameValueCollection data);
+
+ byte[] UploadValues(string address, string method, NameValueCollection data);
+ byte[] UploadValues(Uri address, string method, NameValueCollection data);
+ string UploadString(string address, string data);
+ string UploadString(Uri address, string data);
+ string UploadString(string address, string method, string data);
+ string UploadString(Uri address, string method, string data);
+ string DownloadString(string address);
+
+ ///
+ /// Downloads the requested resource as a . The resource to download is specified as a .
+ ///
+ ///
+ ///
+ /// A containing the requested resource.
+ ///
+ /// A object containing the URI to download.
+ /// The parameter is null.
+ /// The URI formed by combining and is invalid.-or- An error occurred while downloading the resource. The method has been called simultaneously on multiple threads.
+ string DownloadString(Uri address);
+
+ ///
+ /// Opens a readable stream containing the specified resource. This method does not block the calling thread.
+ ///
+ /// The URI of the resource to retrieve.
+ /// The parameter is null.
+ /// The URI formed by combining and address is invalid.-or- An error occurred while downloading the resource. -or- An error occurred while opening the stream.
+ void OpenReadAsync(Uri address);
+
+ void OpenReadAsync(Uri address, object userToken);
+
+ ///
+ /// Opens a stream for writing data to the specified resource. This method does not block the calling thread.
+ ///
+ /// The URI of the resource to receive the data.
+ /// The parameter is null.
+ void OpenWriteAsync(Uri address);
+
+ void OpenWriteAsync(Uri address, string method);
+ void OpenWriteAsync(Uri address, string method, object userToken);
+
+ ///
+ /// Downloads the resource specified as a . This method does not block the calling thread.
+ ///
+ /// A containing the URI to download.
+ /// The parameter is null.
+ /// The URI formed by combining and is invalid.-or- An error occurred while downloading the resource.
+ void DownloadStringAsync(Uri address);
+
+ void DownloadStringAsync(Uri address, object userToken);
+
+ ///
+ /// Downloads the resource as a array from the URI specified as an asynchronous operation.
+ ///
+ /// A containing the URI to download.
+ /// The parameter is null.
+ /// The URI formed by combining and is invalid.-or- An error occurred while downloading the resource.
+ void DownloadDataAsync(Uri address);
+
+ void DownloadDataAsync(Uri address, object userToken);
+ void DownloadFileAsync(Uri address, string fileName);
+ void DownloadFileAsync(Uri address, string fileName, object userToken);
+ void UploadStringAsync(Uri address, string data);
+ void UploadStringAsync(Uri address, string method, string data);
+ void UploadStringAsync(Uri address, string method, string data, object userToken);
+ void UploadDataAsync(Uri address, byte[] data);
+ void UploadDataAsync(Uri address, string method, byte[] data);
+ void UploadDataAsync(Uri address, string method, byte[] data, object userToken);
+ void UploadFileAsync(Uri address, string fileName);
+ void UploadFileAsync(Uri address, string method, string fileName);
+ void UploadFileAsync(Uri address, string method, string fileName, object userToken);
+
+ ///
+ /// Uploads the data in the specified name/value collection to the resource identified by the specified URI. This method does not block the calling thread.
+ ///
+ /// The URI of the resource to receive the collection. This URI must identify a resource that can accept a request sent with the default method. See remarks.
+ /// The to send to the resource.
+ /// The parameter is null.-or-The parameter is null.The URI formed by combining and is invalid.-or- There was no response from the server hosting the resource.
+ void UploadValuesAsync(Uri address, NameValueCollection data);
+
+ void UploadValuesAsync(Uri address, string method, NameValueCollection data);
+ void UploadValuesAsync(Uri address, string method, NameValueCollection data, object userToken);
+
+ ///
+ /// Cancels a pending asynchronous operation.
+ ///
+ ///
+ void CancelAsync();
+
+ System.Threading.Tasks.Task DownloadStringTaskAsync(string address);
+
+ ///
+ /// Downloads the resource as a from the URI specified as an asynchronous operation using a task object.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation. The property on the task object returns a array containing the downloaded resource.
+ ///
+ /// The URI of the resource to download.
+ /// The parameter is null.
+ /// The URI formed by combining and is invalid.-or- An error occurred while downloading the resource.
+ System.Threading.Tasks.Task DownloadStringTaskAsync(Uri address);
+
+ System.Threading.Tasks.Task OpenReadTaskAsync(string address);
+
+ ///
+ /// Opens a readable stream containing the specified resource as an asynchronous operation using a task object.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation. The property on the task object returns a used to read data from a resource.
+ ///
+ /// The URI of the resource to retrieve.The parameter is null. The URI formed by combining and address is invalid.-or- An error occurred while downloading the resource. -or- An error occurred while opening the stream.
+ System.Threading.Tasks.Task OpenReadTaskAsync(Uri address);
+
+ System.Threading.Tasks.Task OpenWriteTaskAsync(string address);
+
+ ///
+ /// Opens a stream for writing data to the specified resource as an asynchronous operation using a task object.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation. The property on the task object returns a used to write data to the resource.
+ ///
+ /// The URI of the resource to receive the data.The parameter is null. The URI formed by combining and is invalid.-or- An error occurred while opening the stream.
+ System.Threading.Tasks.Task OpenWriteTaskAsync(Uri address);
+
+ System.Threading.Tasks.Task OpenWriteTaskAsync(string address, string method);
+ System.Threading.Tasks.Task OpenWriteTaskAsync(Uri address, string method);
+ System.Threading.Tasks.Task UploadStringTaskAsync(string address, string data);
+ System.Threading.Tasks.Task UploadStringTaskAsync(Uri address, string data);
+ System.Threading.Tasks.Task UploadStringTaskAsync(string address, string method, string data);
+ System.Threading.Tasks.Task UploadStringTaskAsync(Uri address, string method, string data);
+ System.Threading.Tasks.Task DownloadDataTaskAsync(string address);
+
+ ///
+ /// Downloads the resource as a array from the URI specified as an asynchronous operation using a task object.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation. The property on the task object returns a array containing the downloaded resource.
+ ///
+ /// The URI of the resource to download.The parameter is null. The URI formed by combining and is invalid.-or- An error occurred while downloading the resource.
+ System.Threading.Tasks.Task DownloadDataTaskAsync(Uri address);
+
+ System.Threading.Tasks.Task DownloadFileTaskAsync(string address, string fileName);
+ System.Threading.Tasks.Task DownloadFileTaskAsync(Uri address, string fileName);
+ System.Threading.Tasks.Task UploadDataTaskAsync(string address, byte[] data);
+ System.Threading.Tasks.Task UploadDataTaskAsync(Uri address, byte[] data);
+ System.Threading.Tasks.Task UploadDataTaskAsync(string address, string method, byte[] data);
+ System.Threading.Tasks.Task UploadDataTaskAsync(Uri address, string method, byte[] data);
+ System.Threading.Tasks.Task UploadFileTaskAsync(string address, string fileName);
+ System.Threading.Tasks.Task UploadFileTaskAsync(Uri address, string fileName);
+ System.Threading.Tasks.Task UploadFileTaskAsync(string address, string method, string fileName);
+ System.Threading.Tasks.Task UploadFileTaskAsync(Uri address, string method, string fileName);
+ System.Threading.Tasks.Task UploadValuesTaskAsync(string address, NameValueCollection data);
+ System.Threading.Tasks.Task UploadValuesTaskAsync(string address, string method, NameValueCollection data);
+
+ ///
+ /// Uploads the specified name/value collection to the resource identified by the specified URI as an asynchronous operation using a task object.
+ ///
+ ///
+ ///
+ /// Returns .The task object representing the asynchronous operation. The property on the task object returns a array containing the response sent by the server.
+ ///
+ /// The URI of the resource to receive the collection.The to send to the resource.The parameter is null.-or-The parameter is null.The URI formed by combining , and is invalid.-or- An error occurred while opening the stream.-or- There was no response from the server hosting the resource.-or- The Content-type header value is not null and is not application/x-www-form-urlencoded.
+ System.Threading.Tasks.Task UploadValuesTaskAsync(Uri address, NameValueCollection data);
+
+ System.Threading.Tasks.Task UploadValuesTaskAsync(Uri address, string method, NameValueCollection data);
+
+ ///
+ /// Gets and sets the used to upload and download strings.
+ ///
+ ///
+ ///
+ /// A that is used to encode strings. The default value of this property is the encoding returned by .
+ ///
+ System.Text.Encoding Encoding { get; set; }
+
+ ///
+ /// Gets or sets the base URI for requests made by a .
+ ///
+ ///
+ ///
+ /// A containing the base URI for requests made by a or if no base address has been specified.
+ ///
+ /// is set to an invalid URI. The inner exception may contain information that will help you locate the error.
+ string BaseAddress { get; set; }
+
+ ///
+ /// Gets or sets the network credentials that are sent to the host and used to authenticate the request.
+ ///
+ ///
+ ///
+ /// An containing the authentication credentials for the request. The default is null.
+ ///
+ ///
+ ICredentials Credentials { get; set; }
+
+ ///
+ /// Gets or sets a value that controls whether the are sent with requests.
+ ///
+ ///
+ ///
+ /// true if the default credentials are used{ throw new NotImplementedException();} otherwise false. The default value is false.
+ ///
+ ///
+ bool UseDefaultCredentials { get; set; }
+
+ ///
+ /// Gets or sets a collection of header name/value pairs associated with the request.
+ ///
+ ///
+ ///
+ /// A containing header name/value pairs associated with this request.
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
+ WebHeaderCollection Headers { get; set; }
+
+ ///
+ /// Gets or sets a collection of query name/value pairs associated with the request.
+ ///
+ ///
+ ///
+ /// A that contains query name/value pairs associated with the request. If no pairs are associated with the request, the value is an empty .
+ ///
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
+ NameValueCollection QueryString { get; set; }
+
+ ///
+ /// Gets a collection of header name/value pairs associated with the response.
+ ///
+ ///
+ ///
+ /// A containing header name/value pairs associated with the response, or null if no response has been received.
+ ///
+ ///
+ WebHeaderCollection ResponseHeaders { get; }
+
+ ///
+ /// Gets or sets the proxy used by this object.
+ ///
+ ///
+ ///
+ /// An instance used to send requests.
+ ///
+ /// is set to null.
+ IWebProxy Proxy { get; set; }
+
+ ///
+ /// Gets or sets the application's cache policy for any resources obtained by this WebClient instance using objects.
+ ///
+ ///
+ ///
+ /// A object that represents the application's caching requirements.
+ ///
+ RequestCachePolicy CachePolicy { get; set; }
+
+ ///
+ /// Gets whether a Web request is in progress.
+ ///
+ ///
+ ///
+ /// true if the Web request is still in progress{ throw new NotImplementedException();} otherwise false.
+ ///
+ bool IsBusy { get; }
+
+ ///
+ /// Occurs when an asynchronous operation to open a stream containing a resource completes.
+ ///
+ event OpenReadCompletedEventHandler OpenReadCompleted;
+
+ ///
+ /// Occurs when an asynchronous operation to open a stream to write data to a resource completes.
+ ///
+ event OpenWriteCompletedEventHandler OpenWriteCompleted;
+
+ ///
+ /// Occurs when an asynchronous resource-download operation completes.
+ ///
+ event DownloadStringCompletedEventHandler DownloadStringCompleted;
+
+ ///
+ /// Occurs when an asynchronous data download operation completes.
+ ///
+ event DownloadDataCompletedEventHandler DownloadDataCompleted;
+
+ ///
+ /// Occurs when an asynchronous file download operation completes.
+ ///
+ event AsyncCompletedEventHandler DownloadFileCompleted;
+
+ ///
+ /// Occurs when an asynchronous string-upload operation completes.
+ ///
+ event UploadStringCompletedEventHandler UploadStringCompleted;
+
+ ///
+ /// Occurs when an asynchronous data-upload operation completes.
+ ///
+ event UploadDataCompletedEventHandler UploadDataCompleted;
+
+ ///
+ /// Occurs when an asynchronous file-upload operation completes.
+ ///
+ event UploadFileCompletedEventHandler UploadFileCompleted;
+
+ ///
+ /// Occurs when an asynchronous upload of a name/value collection completes.
+ ///
+ event UploadValuesCompletedEventHandler UploadValuesCompleted;
+
+ ///
+ /// Occurs when an asynchronous download operation successfully transfers some or all of the data.
+ ///
+ event DownloadProgressChangedEventHandler DownloadProgressChanged;
+
+ ///
+ /// Occurs when an asynchronous upload operation successfully transfers some or all of the data.
+ ///
+ event UploadProgressChangedEventHandler UploadProgressChanged;
+ }
+}
\ No newline at end of file
diff --git a/src/Networking/WebClient.cs b/src/Networking/WebClient.cs
new file mode 100644
index 0000000..e16ea72
--- /dev/null
+++ b/src/Networking/WebClient.cs
@@ -0,0 +1,623 @@
+using System;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Net;
+using System.Net.Cache;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Rothko
+{
+ public class WebClient : IWebClient
+ {
+ private readonly System.Net.WebClient innerWebClient;
+
+ public WebClient()
+ {
+ innerWebClient = new System.Net.WebClient();
+
+ HookEvents();
+ }
+
+ public byte[] DownloadData(string address)
+ {
+ return innerWebClient.DownloadData(address);
+ }
+
+ public byte[] DownloadData(Uri address)
+ {
+ return innerWebClient.DownloadData(address);
+ }
+
+ public void DownloadFile(string address, string fileName)
+ {
+ innerWebClient.DownloadFile(address, fileName);
+ }
+
+ public void DownloadFile(Uri address, string fileName)
+ {
+ innerWebClient.DownloadFile(address, fileName);
+ }
+
+ public System.IO.Stream OpenRead(string address)
+ {
+ return innerWebClient.OpenRead(address);
+ }
+
+ public System.IO.Stream OpenRead(Uri address)
+ {
+ return innerWebClient.OpenRead(address);
+ }
+
+ public System.IO.Stream OpenWrite(string address)
+ {
+ return innerWebClient.OpenWrite(address);
+ }
+
+ public System.IO.Stream OpenWrite(Uri address)
+ {
+ return innerWebClient.OpenWrite(address);
+ }
+
+ public System.IO.Stream OpenWrite(string address, string method)
+ {
+ return innerWebClient.OpenWrite(address, method);
+ }
+
+ public System.IO.Stream OpenWrite(Uri address, string method)
+ {
+ return innerWebClient.OpenWrite(address, method);
+ }
+
+ public byte[] UploadData(string address, byte[] data)
+ {
+ return innerWebClient.UploadData(address, data);
+ }
+
+ public byte[] UploadData(Uri address, byte[] data)
+ {
+ return innerWebClient.UploadData(address, data);
+ }
+
+ public byte[] UploadData(string address, string method, byte[] data)
+ {
+ return innerWebClient.UploadData(address, method, data);
+ }
+
+ public byte[] UploadData(Uri address, string method, byte[] data)
+ {
+ return innerWebClient.UploadData(address, method, data);
+ }
+
+ public byte[] UploadFile(string address, string fileName)
+ {
+ return innerWebClient.UploadFile(address, fileName);
+ }
+
+ public byte[] UploadFile(Uri address, string fileName)
+ {
+ return innerWebClient.UploadFile(address, fileName);
+ }
+
+ public byte[] UploadFile(string address, string method, string fileName)
+ {
+ return innerWebClient.UploadFile(address, method, fileName);
+ }
+
+ public byte[] UploadFile(Uri address, string method, string fileName)
+ {
+ return innerWebClient.UploadFile(address, method, fileName);
+ }
+
+ public byte[] UploadValues(string address, NameValueCollection data)
+ {
+ return innerWebClient.UploadValues(address, data);
+ }
+
+ public byte[] UploadValues(Uri address, NameValueCollection data)
+ {
+ return innerWebClient.UploadValues(address, data);
+ }
+
+ public byte[] UploadValues(string address, string method, NameValueCollection data)
+ {
+ return innerWebClient.UploadValues(address, method, data);
+ }
+
+ public byte[] UploadValues(Uri address, string method, NameValueCollection data)
+ {
+ return innerWebClient.UploadValues(address, method, data);
+ }
+
+ public string UploadString(string address, string data)
+ {
+ return innerWebClient.UploadString(address, data);
+ }
+
+ public string UploadString(Uri address, string data)
+ {
+ return innerWebClient.UploadString(address, data);
+ }
+
+ public string UploadString(string address, string method, string data)
+ {
+ return innerWebClient.UploadString(address, method, data);
+ }
+
+ public string UploadString(Uri address, string method, string data)
+ {
+ return innerWebClient.UploadString(address, method, data);
+ }
+
+ public string DownloadString(string address)
+ {
+ return innerWebClient.DownloadString(address);
+ }
+
+ public string DownloadString(Uri address)
+ {
+ return innerWebClient.DownloadString(address);
+ }
+
+ public void OpenReadAsync(Uri address)
+ {
+ innerWebClient.OpenReadAsync(address);
+ }
+
+ public void OpenReadAsync(Uri address, object userToken)
+ {
+ innerWebClient.OpenReadAsync(address, userToken);
+ }
+
+ public void OpenWriteAsync(Uri address)
+ {
+ innerWebClient.OpenWriteAsync(address);
+ }
+
+ public void OpenWriteAsync(Uri address, string method)
+ {
+ innerWebClient.OpenWriteAsync(address, method);
+ }
+
+ public void OpenWriteAsync(Uri address, string method, object userToken)
+ {
+ innerWebClient.OpenWriteAsync(address, method, userToken);
+ }
+
+ public void DownloadStringAsync(Uri address)
+ {
+ innerWebClient.DownloadStringAsync(address);
+ }
+
+ public void DownloadStringAsync(Uri address, object userToken)
+ {
+ innerWebClient.DownloadStringAsync(address, userToken);
+ }
+
+ public void DownloadDataAsync(Uri address)
+ {
+ innerWebClient.DownloadDataAsync(address);
+ }
+
+ public void DownloadDataAsync(Uri address, object userToken)
+ {
+ innerWebClient.DownloadDataAsync(address, userToken);
+ }
+
+ public void DownloadFileAsync(Uri address, string fileName)
+ {
+ innerWebClient.DownloadFileAsync(address, fileName);
+ }
+
+ public void DownloadFileAsync(Uri address, string fileName, object userToken)
+ {
+ innerWebClient.DownloadFileAsync(address, fileName, userToken);
+ }
+
+ public void UploadStringAsync(Uri address, string data)
+ {
+ innerWebClient.UploadStringAsync(address, data);
+ }
+
+ public void UploadStringAsync(Uri address, string method, string data)
+ {
+ innerWebClient.UploadStringAsync(address, method, data);
+ }
+
+ public void UploadStringAsync(Uri address, string method, string data, object userToken)
+ {
+ innerWebClient.UploadStringAsync(address, method, data, userToken);
+ }
+
+ public void UploadDataAsync(Uri address, byte[] data)
+ {
+ innerWebClient.UploadDataAsync(address, data);
+ }
+
+ public void UploadDataAsync(Uri address, string method, byte[] data)
+ {
+ innerWebClient.UploadDataAsync(address, method, data);
+ }
+
+ public void UploadDataAsync(Uri address, string method, byte[] data, object userToken)
+ {
+ innerWebClient.UploadDataAsync(address, method, data, userToken);
+ }
+
+ public void UploadFileAsync(Uri address, string fileName)
+ {
+ innerWebClient.UploadFileAsync(address, fileName);
+ }
+
+ public void UploadFileAsync(Uri address, string method, string fileName)
+ {
+ innerWebClient.UploadFileAsync(address, method, fileName);
+ }
+
+ public void UploadFileAsync(Uri address, string method, string fileName, object userToken)
+ {
+ innerWebClient.UploadFileAsync(address, method, fileName, userToken);
+ }
+
+ public void UploadValuesAsync(Uri address, NameValueCollection data)
+ {
+ innerWebClient.UploadValuesAsync(address, data);
+ }
+
+ public void UploadValuesAsync(Uri address, string method, NameValueCollection data)
+ {
+ innerWebClient.UploadValuesAsync(address, method, data);
+ }
+
+ public void UploadValuesAsync(Uri address, string method, NameValueCollection data, object userToken)
+ {
+ innerWebClient.UploadValuesAsync(address, method, data, userToken);
+ }
+
+ public void CancelAsync()
+ {
+ innerWebClient.CancelAsync();
+ }
+
+ public Task DownloadStringTaskAsync(string address)
+ {
+ return innerWebClient.DownloadStringTaskAsync(address);
+ }
+
+ public Task DownloadStringTaskAsync(Uri address)
+ {
+ return innerWebClient.DownloadStringTaskAsync(address);
+ }
+
+ public Task OpenReadTaskAsync(string address)
+ {
+ return innerWebClient.OpenReadTaskAsync(address);
+ }
+
+ public Task OpenReadTaskAsync(Uri address)
+ {
+ return innerWebClient.OpenReadTaskAsync(address);
+ }
+
+ public Task OpenWriteTaskAsync(string address)
+ {
+ return innerWebClient.OpenWriteTaskAsync(address);
+ }
+
+ public Task OpenWriteTaskAsync(Uri address)
+ {
+ return innerWebClient.OpenWriteTaskAsync(address);
+ }
+
+ public Task OpenWriteTaskAsync(string address, string method)
+ {
+ return innerWebClient.OpenWriteTaskAsync(address, method);
+ }
+
+ public Task OpenWriteTaskAsync(Uri address, string method)
+ {
+ return innerWebClient.OpenWriteTaskAsync(address, method);
+ }
+
+ public Task UploadStringTaskAsync(string address, string data)
+ {
+ return innerWebClient.UploadStringTaskAsync(address, data);
+ }
+
+ public Task UploadStringTaskAsync(Uri address, string data)
+ {
+ return innerWebClient.UploadStringTaskAsync(address, data);
+ }
+
+ public Task UploadStringTaskAsync(string address, string method, string data)
+ {
+ return innerWebClient.UploadStringTaskAsync(address, method, data);
+ }
+
+ public Task UploadStringTaskAsync(Uri address, string method, string data)
+ {
+ return innerWebClient.UploadStringTaskAsync(address, method, data);
+ }
+
+ public Task DownloadDataTaskAsync(string address)
+ {
+ return innerWebClient.DownloadDataTaskAsync(address);
+ }
+
+ public Task DownloadDataTaskAsync(Uri address)
+ {
+ return innerWebClient.DownloadDataTaskAsync(address);
+ }
+
+ public Task DownloadFileTaskAsync(string address, string fileName)
+ {
+ return innerWebClient.DownloadFileTaskAsync(address, fileName);
+ }
+
+ public Task DownloadFileTaskAsync(Uri address, string fileName)
+ {
+ return innerWebClient.DownloadFileTaskAsync(address, fileName);
+ }
+
+ public Task UploadDataTaskAsync(string address, byte[] data)
+ {
+ return innerWebClient.UploadDataTaskAsync(address, data);
+ }
+
+ public Task UploadDataTaskAsync(Uri address, byte[] data)
+ {
+ return innerWebClient.UploadDataTaskAsync(address, data);
+ }
+
+ public Task UploadDataTaskAsync(string address, string method, byte[] data)
+ {
+ return innerWebClient.UploadDataTaskAsync(address, method, data);
+ }
+
+ public Task UploadDataTaskAsync(Uri address, string method, byte[] data)
+ {
+ return innerWebClient.UploadDataTaskAsync(address, method, data);
+ }
+
+ public Task UploadFileTaskAsync(string address, string fileName)
+ {
+ return innerWebClient.UploadFileTaskAsync(address, fileName);
+ }
+
+ public Task UploadFileTaskAsync(Uri address, string fileName)
+ {
+ return innerWebClient.UploadFileTaskAsync(address, fileName);
+ }
+
+ public Task UploadFileTaskAsync(string address, string method, string fileName)
+ {
+ return innerWebClient.UploadFileTaskAsync(address, method, fileName);
+ }
+
+ public Task UploadFileTaskAsync(Uri address, string method, string fileName)
+ {
+ return innerWebClient.UploadFileTaskAsync(address, method, fileName);
+ }
+
+ public Task UploadValuesTaskAsync(string address, NameValueCollection data)
+ {
+ return innerWebClient.UploadValuesTaskAsync(address, data);
+ }
+
+ public Task UploadValuesTaskAsync(string address, string method, NameValueCollection data)
+ {
+ return innerWebClient.UploadValuesTaskAsync(address, method, data);
+ }
+
+ public Task UploadValuesTaskAsync(Uri address, NameValueCollection data)
+ {
+ return innerWebClient.UploadValuesTaskAsync(address, data);
+ }
+ public Task UploadValuesTaskAsync(Uri address, string method, NameValueCollection data)
+ {
+ return innerWebClient.UploadValuesTaskAsync(address, method, data);
+ }
+
+ public Encoding Encoding
+ {
+ get { return innerWebClient.Encoding; }
+ set { innerWebClient.Encoding = value; }
+ }
+
+ public string BaseAddress
+ {
+ get { return innerWebClient.BaseAddress; }
+ set { innerWebClient.BaseAddress = value; }
+ }
+
+ public ICredentials Credentials
+ {
+ get { return innerWebClient.Credentials; }
+ set { innerWebClient.Credentials = value; }
+ }
+
+ public bool UseDefaultCredentials
+ {
+ get { return innerWebClient.UseDefaultCredentials; }
+ set { innerWebClient.UseDefaultCredentials = value; }
+ }
+
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
+ public WebHeaderCollection Headers
+ {
+ get { return innerWebClient.Headers; }
+ set { innerWebClient.Headers = value; }
+ }
+
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
+ public NameValueCollection QueryString
+ {
+ get { return innerWebClient.QueryString; }
+ set { innerWebClient.QueryString = value; }
+ }
+
+ public WebHeaderCollection ResponseHeaders
+ {
+ get { return innerWebClient.ResponseHeaders; }
+ }
+
+ public IWebProxy Proxy
+ {
+ get { return innerWebClient.Proxy; }
+ set { innerWebClient.Proxy = value; }
+ }
+
+ public RequestCachePolicy CachePolicy
+ {
+ get { return innerWebClient.CachePolicy; }
+ set { innerWebClient.CachePolicy = value; }
+ }
+
+ public bool IsBusy
+ {
+ get { return innerWebClient.IsBusy; }
+ }
+
+ private void HookEvents()
+ {
+ innerWebClient.OpenReadCompleted += OnOpenReadCompleted;
+ innerWebClient.OpenWriteCompleted += OnOpenWriteCompleted;
+
+ innerWebClient.DownloadDataCompleted += DownloadDataCompleted;
+ innerWebClient.DownloadFileCompleted += DownloadFileCompleted;
+ innerWebClient.DownloadStringCompleted += DownloadStringCompleted;
+ innerWebClient.UploadDataCompleted += UploadDataCompleted;
+ innerWebClient.UploadFileCompleted += UploadFileCompleted;
+ innerWebClient.UploadStringCompleted += UploadStringCompleted;
+ innerWebClient.UploadValuesCompleted += UploadValuesCompleted;
+
+ innerWebClient.DownloadProgressChanged += DownloadProgressChanged;
+ innerWebClient.UploadProgressChanged += UploadProgressChanged;
+ }
+
+ private void UnhookEvents()
+ {
+ innerWebClient.OpenReadCompleted -= OnOpenReadCompleted;
+ innerWebClient.OpenWriteCompleted -= OnOpenWriteCompleted;
+
+ innerWebClient.DownloadDataCompleted -= DownloadDataCompleted;
+ innerWebClient.DownloadFileCompleted -= DownloadFileCompleted;
+ innerWebClient.DownloadStringCompleted -= DownloadStringCompleted;
+ innerWebClient.UploadDataCompleted -= UploadDataCompleted;
+ innerWebClient.UploadFileCompleted -= UploadFileCompleted;
+ innerWebClient.UploadStringCompleted -= UploadStringCompleted;
+ innerWebClient.UploadValuesCompleted -= UploadValuesCompleted;
+
+ innerWebClient.DownloadProgressChanged -= DownloadProgressChanged;
+ innerWebClient.UploadProgressChanged -= UploadProgressChanged;
+ }
+
+ public event OpenReadCompletedEventHandler OpenReadCompleted;
+ public event OpenWriteCompletedEventHandler OpenWriteCompleted;
+ public event DownloadStringCompletedEventHandler DownloadStringCompleted;
+ public event DownloadDataCompletedEventHandler DownloadDataCompleted;
+ public event DownloadProgressChangedEventHandler DownloadProgressChanged;
+ public event AsyncCompletedEventHandler DownloadFileCompleted;
+ public event UploadStringCompletedEventHandler UploadStringCompleted;
+ public event UploadDataCompletedEventHandler UploadDataCompleted;
+ public event UploadFileCompletedEventHandler UploadFileCompleted;
+ public event UploadValuesCompletedEventHandler UploadValuesCompleted;
+ public event UploadProgressChangedEventHandler UploadProgressChanged;
+
+ #region Event Invocators
+ protected virtual void OnOpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
+ {
+ OpenReadCompletedEventHandler handler = OpenReadCompleted;
+ if (handler != null) handler(this, e);
+ }
+
+ protected virtual void OnOpenWriteCompleted(object sender, OpenWriteCompletedEventArgs e)
+ {
+ OpenWriteCompletedEventHandler handler = OpenWriteCompleted;
+ if (handler != null) handler(this, e);
+ }
+
+ protected virtual void OnDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
+ {
+ DownloadStringCompletedEventHandler handler = DownloadStringCompleted;
+ if (handler != null) handler(this, e);
+ }
+
+ protected virtual void OnDownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
+ {
+ DownloadDataCompletedEventHandler handler = DownloadDataCompleted;
+ if (handler != null) handler(this, e);
+ }
+
+ protected virtual void OnDownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
+ {
+ AsyncCompletedEventHandler handler = DownloadFileCompleted;
+ if (handler != null) handler(this, e);
+ }
+
+ protected virtual void OnUploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
+ {
+ UploadStringCompletedEventHandler handler = UploadStringCompleted;
+ if (handler != null) handler(this, e);
+ }
+
+ protected virtual void OnUploadDataCompleted(object sender, UploadDataCompletedEventArgs e)
+ {
+ UploadDataCompletedEventHandler handler = UploadDataCompleted;
+ if (handler != null) handler(this, e);
+ }
+
+ protected virtual void OnUploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
+ {
+ UploadFileCompletedEventHandler handler = UploadFileCompleted;
+ if (handler != null) handler(this, e);
+ }
+
+ protected virtual void OnUploadValuesCompleted(object sender, UploadValuesCompletedEventArgs e)
+ {
+ UploadValuesCompletedEventHandler handler = UploadValuesCompleted;
+ if (handler != null) handler(this, e);
+ }
+
+ protected virtual void OnDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
+ {
+ DownloadProgressChangedEventHandler handler = DownloadProgressChanged;
+ if (handler != null) handler(this, e);
+ }
+
+ protected virtual void OnUploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
+ {
+ UploadProgressChangedEventHandler handler = UploadProgressChanged;
+ if (handler != null) handler(this, e);
+ }
+ #endregion
+
+ ///
+ /// Releases all resources used by the .
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Releases the unmanaged resources used by the and
+ /// optionally releases the managed resources.
+ ///
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (innerWebClient != null)
+ {
+ UnhookEvents();
+ innerWebClient.Dispose();
+ }
+ }
+ }
+ }
+}
diff --git a/src/OperatingSystem.cs b/src/OperatingSystem.cs
deleted file mode 100644
index 7808692..0000000
--- a/src/OperatingSystem.cs
+++ /dev/null
@@ -1,585 +0,0 @@
-using System;
-using System.Globalization;
-using System.Runtime.Serialization;
-using Rothko.Win32;
-
-namespace Rothko
-{
- ///
- /// Represents information about an operating system, such as the version and platform identifier. This class cannot be inherited.
- ///
- public sealed class OperatingSystem : IOperatingSystem
- {
- #region PRODUCT
- private const int PRODUCT_UNDEFINED = 0x00000000;
- private const int PRODUCT_ULTIMATE = 0x00000001;
- private const int PRODUCT_HOME_BASIC = 0x00000002;
- private const int PRODUCT_HOME_PREMIUM = 0x00000003;
- private const int PRODUCT_ENTERPRISE = 0x00000004;
- private const int PRODUCT_HOME_BASIC_N = 0x00000005;
- private const int PRODUCT_BUSINESS = 0x00000006;
- private const int PRODUCT_STANDARD_SERVER = 0x00000007;
- private const int PRODUCT_DATACENTER_SERVER = 0x00000008;
- private const int PRODUCT_SMALLBUSINESS_SERVER = 0x00000009;
- private const int PRODUCT_ENTERPRISE_SERVER = 0x0000000A;
- private const int PRODUCT_STARTER = 0x0000000B;
- private const int PRODUCT_DATACENTER_SERVER_CORE = 0x0000000C;
- private const int PRODUCT_STANDARD_SERVER_CORE = 0x0000000D;
- private const int PRODUCT_ENTERPRISE_SERVER_CORE = 0x0000000E;
- private const int PRODUCT_ENTERPRISE_SERVER_IA64 = 0x0000000F;
- private const int PRODUCT_BUSINESS_N = 0x00000010;
- private const int PRODUCT_WEB_SERVER = 0x00000011;
- private const int PRODUCT_CLUSTER_SERVER = 0x00000012;
- private const int PRODUCT_STORAGE_EXPRESS_SERVER = 0x00000014;
- private const int PRODUCT_STORAGE_STANDARD_SERVER = 0x00000015;
- private const int PRODUCT_STORAGE_WORKGROUP_SERVER = 0x00000016;
- private const int PRODUCT_STORAGE_ENTERPRISE_SERVER = 0x00000017;
- private const int PRODUCT_SERVER_FOR_SMALLBUSINESS = 0x00000018;
- private const int PRODUCT_SMALLBUSINESS_SERVER_PREMIUM = 0x00000019;
- private const int PRODUCT_HOME_PREMIUM_N = 0x0000001A;
- private const int PRODUCT_ENTERPRISE_N = 0x0000001B;
- private const int PRODUCT_ULTIMATE_N = 0x0000001C;
- private const int PRODUCT_WEB_SERVER_CORE = 0x0000001D;
- private const int PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT = 0x0000001E;
- private const int PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY = 0x0000001F;
- private const int PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING = 0x00000020;
- private const int PRODUCT_SERVER_FOUNDATION = 0x00000021;
- private const int PRODUCT_HOME_PREMIUM_SERVER = 0x00000022;
- private const int PRODUCT_SERVER_FOR_SMALLBUSINESS_V = 0x00000023;
- private const int PRODUCT_STANDARD_SERVER_V = 0x00000024;
- private const int PRODUCT_DATACENTER_SERVER_V = 0x00000025;
- private const int PRODUCT_ENTERPRISE_SERVER_V = 0x00000026;
- private const int PRODUCT_DATACENTER_SERVER_CORE_V = 0x00000027;
- private const int PRODUCT_STANDARD_SERVER_CORE_V = 0x00000028;
- private const int PRODUCT_ENTERPRISE_SERVER_CORE_V = 0x00000029;
- private const int PRODUCT_HYPERV = 0x0000002A;
- private const int PRODUCT_STORAGE_EXPRESS_SERVER_CORE = 0x0000002B;
- private const int PRODUCT_STORAGE_STANDARD_SERVER_CORE = 0x0000002C;
- private const int PRODUCT_STORAGE_WORKGROUP_SERVER_CORE = 0x0000002D;
- private const int PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE = 0x0000002E;
- private const int PRODUCT_STARTER_N = 0x0000002F;
- private const int PRODUCT_PROFESSIONAL = 0x00000030;
- private const int PRODUCT_PROFESSIONAL_N = 0x00000031;
- private const int PRODUCT_SB_SOLUTION_SERVER = 0x00000032;
- private const int PRODUCT_SERVER_FOR_SB_SOLUTIONS = 0x00000033;
- private const int PRODUCT_STANDARD_SERVER_SOLUTIONS = 0x00000034;
- private const int PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE = 0x00000035;
- private const int PRODUCT_SB_SOLUTION_SERVER_EM = 0x00000036;
- private const int PRODUCT_SERVER_FOR_SB_SOLUTIONS_EM = 0x00000037;
- private const int PRODUCT_SOLUTION_EMBEDDEDSERVER = 0x00000038;
- private const int PRODUCT_SOLUTION_EMBEDDEDSERVER_CORE = 0x00000039;
- private const int PRODUCT_ESSENTIALBUSINESS_SERVER_MGMT = 0x0000003B;
- private const int PRODUCT_ESSENTIALBUSINESS_SERVER_ADDL = 0x0000003C;
- private const int PRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC = 0x0000003D;
- private const int PRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC = 0x0000003E;
- private const int PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE = 0x0000003F;
- private const int PRODUCT_CLUSTER_SERVER_V = 0x00000040;
- private const int PRODUCT_EMBEDDED = 0x00000041;
- private const int PRODUCT_STARTER_E = 0x00000042;
- private const int PRODUCT_HOME_BASIC_E = 0x00000043;
- private const int PRODUCT_HOME_PREMIUM_E = 0x00000044;
- private const int PRODUCT_PROFESSIONAL_E = 0x00000045;
- private const int PRODUCT_ENTERPRISE_E = 0x00000046;
- private const int PRODUCT_ULTIMATE_E = 0x00000047;
- #endregion PRODUCT
-
- #region VERSIONS
- private const int VER_NT_WORKSTATION = 1;
- private const int VER_NT_SERVER = 3;
- private const int VER_SUITE_ENTERPRISE = 2;
- private const int VER_SUITE_DATACENTER = 128;
- private const int VER_SUITE_PERSONAL = 512;
- private const int VER_SUITE_BLADE = 1024;
- #endregion VERSIONS
-
- readonly System.OperatingSystem _operatingSystem;
- private string _edition;
- private string _name;
-
- ///
- /// Initializes a new instance of the class, using the specified platform identifier value and version object.
- ///
- /// A valid instance of class. Usually is given by the Env.OSVersion property.
- public OperatingSystem(System.OperatingSystem operatingSystem)
- {
- _operatingSystem = operatingSystem;
- }
-
- ///
- /// Creates an object that is identical to this instance.
- ///
- ///
- public object Clone()
- {
- return _operatingSystem.Clone();
- }
-
- ///
- /// Populates a object with the data necessary to deserialize this instance.
- ///
- /// The object to populate with serialization information.
- /// The place to store and retrieve serialized data. Reserved for future use.
- /// info is null.
- public void GetObjectData(SerializationInfo info, StreamingContext context)
- {
- _operatingSystem.GetObjectData(info, context);
- }
-
- ///
- /// Gets a enumeration value that identifies the operating system platform.
- ///
- public PlatformID Platform
- {
- get { return _operatingSystem.Platform; }
- }
-
- ///
- /// Gets the service pack version represented by this OperatingSystem object.
- ///
- public string ServicePack
- {
- get { return _operatingSystem.ServicePack; }
- }
-
- ///
- /// Gets a object that identifies the operating system.
- ///
- public Version Version
- {
- get { return _operatingSystem.Version; }
- }
-
- ///
- /// Gets the concatenated string representation of the platform identifier, version, and service pack that are currently installed on the operating system.
- ///
- public string VersionString
- {
- get { return _operatingSystem.VersionString; }
- }
-
- ///
- /// Gets the edition of the operating system running on this computer.
- ///
- public string Edition
- {
- get
- {
- if (_edition != null)
- return _edition;
-
- string edition = String.Empty;
- OsVersionInfoEx osVersion = new OsVersionInfoEx();
-
- if (NativeMethods.GetVersionEx(osVersion))
- {
- switch (osVersion.MajorVersion)
- {
- case 4:
- edition = GetEditionMajorVersionFour(osVersion.ProductType, osVersion.SuiteMask);
- break;
- case 5:
- edition = GetEditionMajorVersionFive(osVersion.MinorVersion, osVersion.ProductType, osVersion.SuiteMask);
- break;
- case 6:
- edition = GetEditionMajorVersionSix(osVersion);
- break;
- }
- }
-
- _edition = edition;
- return edition;
- }
- }
-
- ///
- /// Gets the name of the operating system running on this computer.
- ///
- public string Name
- {
- get
- {
- if (_name != null)
- return _name;
-
- string name = "unknown";
-
- OsVersionInfoEx osVersion = new OsVersionInfoEx();
-
- if (NativeMethods.GetVersionEx(osVersion))
- {
- switch (_operatingSystem.Platform)
- {
- case PlatformID.Win32Windows:
- {
- if (osVersion.MajorVersion == 4)
- {
- name = GetWin32VersionName(osVersion.MinorVersion, osVersion.CSDVersion);
- }
-
- break;
- }
- case PlatformID.Win32NT:
- {
- name = GetWin32NTVersionName(osVersion.MajorVersion, osVersion.MinorVersion, osVersion.ProductType);
- }
-
- break;
- }
- }
-
- _name = name;
- return name;
- }
- }
-
- ///
- /// Converts the value of this object to its equivalent string representation.
- ///
- /// The commercial name of the running operating system.
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations", Justification = "The violation is caused by an exception declaration instead of a thrown exception.")]
- public override string ToString()
- {
- return string.Format(CultureInfo.InvariantCulture, "{0} {1} with {2}", Name, Edition, ServicePack);
- }
-
- private static string GetWin32VersionName(int minorVersion, string csdVersion)
- {
- switch (minorVersion)
- {
- case 0:
- if (csdVersion == "B" || csdVersion == "C")
- {
- return "Windows 95 OSR2";
- }
-
- return "Windows 95";
- case 10:
- if (csdVersion == "A")
- {
- return "Windows 98 Second Edition";
- }
-
- return "Windows 98";
-
- case 90:
- return "Windows Me";
-
- default:
- return string.Empty;
- }
- }
-
- private static string GetWin32NTVersionName(int majorVersion, int minorVersion, int productType)
- {
- switch (majorVersion)
- {
- case 3:
- return "Windows NT 3.51";
- case 4:
- switch (productType)
- {
- case 1:
- return "Windows NT 4.0";
- case 3:
- return "Windows NT 4.0 Server";
- }
-
- return string.Empty;
- case 5:
- switch (minorVersion)
- {
- case 0:
- return "Windows 2000";
- case 1:
- return "Windows XP";
- case 2:
- return "Windows Server 2003";
- }
-
- return string.Empty;
- case 6:
- return GetVersionSixOsName(minorVersion, productType);
- default:
- return string.Empty;
- }
- }
-
- private static string GetVersionSixOsName(int minorVersion, int productType)
- {
- switch (minorVersion)
- {
- case 0:
- switch (productType)
- {
- case 1:
- return "Windows Vista";
- case 3:
- return "Windows Server 2008";
- }
-
- return string.Empty;
- case 1:
- switch (productType)
- {
- case 1:
- return "Windows 7";
- case 3:
- return "Windows Server 2008 R2";
- }
-
- return string.Empty;
- case 2:
- switch (productType)
- {
- case 1:
- return "Windows 8";
- case 3:
- return "Windows Server 2012";
- }
-
- return string.Empty;
- case 3:
- switch (productType)
- {
- case 1:
- return "Windows 8.1";
- case 3:
- return "Windows Server 2012 R2";
- }
-
- return string.Empty;
-
- default:
- return string.Empty;
- }
- }
-
- private static string GetEditionMajorVersionFour(byte productType, short suiteMask)
- {
- if (productType == VER_NT_WORKSTATION)
- {
- // Windows NT 4.0 Workstation
- return "Workstation";
- }
-
- if (productType == VER_NT_SERVER)
- {
- if ((suiteMask & VER_SUITE_ENTERPRISE) != 0)
- {
- // Windows NT 4.0 Server Enterprise
- return "Enterprise Server";
- }
-
- // Windows NT 4.0 Server
- return "Standard Server";
- }
-
- return string.Empty;
- }
-
- private static string GetEditionMajorVersionFive(int minorVersion, byte productType, short suiteMask)
- {
- if (productType == VER_NT_WORKSTATION)
- {
- if ((suiteMask & VER_SUITE_PERSONAL) != 0)
- {
- return "Home";
- }
-
- if (NativeMethods.GetSystemMetrics(SystemMetric.SM_TABLETPC) == 0)
- {
- return "Professional";
- }
-
- return "Tablet PC Edition";
- }
-
-
- if (productType == VER_NT_SERVER)
- {
- if (minorVersion == 0)
- {
- if ((suiteMask & VER_SUITE_DATACENTER) != 0)
- {
- // Windows 2000 Datacenter Server
- return "Datacenter Server";
- }
-
- return (suiteMask & VER_SUITE_ENTERPRISE) != 0 ? "Advanced Server" : "Server";
- }
-
-
- if ((suiteMask & VER_SUITE_DATACENTER) != 0)
- {
- // Windows Server 2003 Datacenter Edition
- return "Datacenter";
- }
-
- if ((suiteMask & VER_SUITE_ENTERPRISE) != 0)
- {
- // Windows Server 2003 Enterprise Edition
- return "Enterprise";
- }
-
- return (suiteMask & VER_SUITE_BLADE) != 0 ? "Web Edition" : "Standard";
- }
-
- return string.Empty;
- }
-
- private static string GetEditionMajorVersionSix(OsVersionInfoEx osVersion)
- {
- int ed;
- if (NativeMethods.GetProductInfo(osVersion.MajorVersion, osVersion.MinorVersion,
- osVersion.ServicePackMajor, osVersion.ServicePackMinor,
- out ed))
- {
- switch (ed)
- {
- case PRODUCT_BUSINESS:
- return "Business";
- case PRODUCT_BUSINESS_N:
- return "Business N";
- case PRODUCT_CLUSTER_SERVER:
- return "HPC Edition";
- case PRODUCT_CLUSTER_SERVER_V:
- return "HPC Edition without Hyper-V";
- case PRODUCT_DATACENTER_SERVER:
- return "Datacenter Server";
- case PRODUCT_DATACENTER_SERVER_CORE:
- return "Datacenter Server (core installation)";
- case PRODUCT_DATACENTER_SERVER_V:
- return "Datacenter Server without Hyper-V";
- case PRODUCT_DATACENTER_SERVER_CORE_V:
- return "Datacenter Server without Hyper-V (core installation)";
- case PRODUCT_EMBEDDED:
- return "Embedded";
- case PRODUCT_ENTERPRISE:
- return "Enterprise";
- case PRODUCT_ENTERPRISE_N:
- return "Enterprise N";
- case PRODUCT_ENTERPRISE_E:
- return "Enterprise E";
- case PRODUCT_ENTERPRISE_SERVER:
- return "Enterprise Server";
- case PRODUCT_ENTERPRISE_SERVER_CORE:
- return "Enterprise Server (core installation)";
- case PRODUCT_ENTERPRISE_SERVER_CORE_V:
- return "Enterprise Server without Hyper-V (core installation)";
- case PRODUCT_ENTERPRISE_SERVER_IA64:
- return "Enterprise Server for Itanium-based Systems";
- case PRODUCT_ENTERPRISE_SERVER_V:
- return "Enterprise Server without Hyper-V";
- case PRODUCT_ESSENTIALBUSINESS_SERVER_MGMT:
- return "Essential Business Server MGMT";
- case PRODUCT_ESSENTIALBUSINESS_SERVER_ADDL:
- return "Essential Business Server ADDL";
- case PRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC:
- return "Essential Business Server MGMTSVC";
- case PRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC:
- return "Essential Business Server ADDLSVC";
- case PRODUCT_HOME_BASIC:
- return "Home Basic";
- case PRODUCT_HOME_BASIC_N:
- return "Home Basic N";
- case PRODUCT_HOME_BASIC_E:
- return "Home Basic E";
- case PRODUCT_HOME_PREMIUM:
- return "Home Premium";
- case PRODUCT_HOME_PREMIUM_N:
- return "Home Premium N";
- case PRODUCT_HOME_PREMIUM_E:
- return "Home Premium E";
- case PRODUCT_HOME_PREMIUM_SERVER:
- return "Home Premium Server";
- case PRODUCT_HYPERV:
- return "Microsoft Hyper-V Server";
- case PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT:
- return "Windows Essential Business Management Server";
- case PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING:
- return "Windows Essential Business Messaging Server";
- case PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY:
- return "Windows Essential Business Security Server";
- case PRODUCT_PROFESSIONAL:
- return "Professional";
- case PRODUCT_PROFESSIONAL_N:
- return "Professional N";
- case PRODUCT_PROFESSIONAL_E:
- return "Professional E";
- case PRODUCT_SB_SOLUTION_SERVER:
- return "SB Solution Server";
- case PRODUCT_SB_SOLUTION_SERVER_EM:
- return "SB Solution Server EM";
- case PRODUCT_SERVER_FOR_SB_SOLUTIONS:
- return "Server for SB Solutions";
- case PRODUCT_SERVER_FOR_SB_SOLUTIONS_EM:
- return "Server for SB Solutions EM";
- case PRODUCT_SERVER_FOR_SMALLBUSINESS:
- return "Windows Essential Server Solutions";
- case PRODUCT_SERVER_FOR_SMALLBUSINESS_V:
- return "Windows Essential Server Solutions without Hyper-V";
- case PRODUCT_SERVER_FOUNDATION:
- return "Server Foundation";
- case PRODUCT_SMALLBUSINESS_SERVER:
- return "Windows Small Business Server";
- case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
- return "Windows Small Business Server Premium";
- case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE:
- return "Windows Small Business Server Premium (core installation)";
- case PRODUCT_SOLUTION_EMBEDDEDSERVER:
- return "Solution Embedded Server";
- case PRODUCT_SOLUTION_EMBEDDEDSERVER_CORE:
- return "Solution Embedded Server (core installation)";
- case PRODUCT_STANDARD_SERVER:
- return "Standard Server";
- case PRODUCT_STANDARD_SERVER_CORE:
- return "Standard Server (core installation)";
- case PRODUCT_STANDARD_SERVER_SOLUTIONS:
- return "Standard Server Solutions";
- case PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE:
- return "Standard Server Solutions (core installation)";
- case PRODUCT_STANDARD_SERVER_CORE_V:
- return "Standard Server without Hyper-V (core installation)";
- case PRODUCT_STANDARD_SERVER_V:
- return "Standard Server without Hyper-V";
- case PRODUCT_STARTER:
- return "Starter";
- case PRODUCT_STARTER_N:
- return "Starter N";
- case PRODUCT_STARTER_E:
- return "Starter E";
- case PRODUCT_STORAGE_ENTERPRISE_SERVER:
- return "Enterprise Storage Server";
- case PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE:
- return "Enterprise Storage Server (core installation)";
- case PRODUCT_STORAGE_EXPRESS_SERVER:
- return "Express Storage Server";
- case PRODUCT_STORAGE_EXPRESS_SERVER_CORE:
- return "Express Storage Server (core installation)";
- case PRODUCT_STORAGE_STANDARD_SERVER:
- return "Standard Storage Server";
- case PRODUCT_STORAGE_STANDARD_SERVER_CORE:
- return "Standard Storage Server (core installation)";
- case PRODUCT_STORAGE_WORKGROUP_SERVER:
- return "Workgroup Storage Server";
- case PRODUCT_STORAGE_WORKGROUP_SERVER_CORE:
- return "Workgroup Storage Server (core installation)";
- case PRODUCT_UNDEFINED:
- return "Unknown product";
- case PRODUCT_ULTIMATE:
- return "Ultimate";
- case PRODUCT_ULTIMATE_N:
- return "Ultimate N";
- case PRODUCT_ULTIMATE_E:
- return "Ultimate E";
- case PRODUCT_WEB_SERVER:
- return "Web Server";
- case PRODUCT_WEB_SERVER_CORE:
- return "Web Server (core installation)";
- }
- }
-
- return string.Empty;
- }
- }
-}
diff --git a/src/OperatingSystemFacade.cs b/src/OperatingSystemFacade.cs
index 3212e3b..ea9ea1d 100644
--- a/src/OperatingSystemFacade.cs
+++ b/src/OperatingSystemFacade.cs
@@ -1,6 +1,8 @@
-namespace Rothko
+using Rothko.Infrastructure;
+
+namespace Rothko
{
- public class OperatingSystemFacade : IOperatingSystemFacade
+ public class OperatingSystemFacade : IOperatingSystem
{
public OperatingSystemFacade()
{
@@ -10,9 +12,11 @@ public OperatingSystemFacade()
Environment = new Environment();
File = new FileFacade();
MemoryMappedFiles = new MemoryMappedFileFactory();
+ Net = new NetFactory();
ProcessLocator = new ProcessLocator();
ProcessStarter = new ProcessStarter();
Registry = new Registry();
+ Browser = new Browser(ProcessStarter, Environment);
}
public IAssemblyFacade Assembly { get; private set; }
@@ -21,8 +25,11 @@ public OperatingSystemFacade()
public IEnvironment Environment { get; private set; }
public IFileFacade File { get; private set; }
public IMemoryMappedFileFactory MemoryMappedFiles { get; private set; }
+ public INetFactory Net { get; private set; }
public IProcessLocator ProcessLocator { get; private set; }
public IProcessStarter ProcessStarter { get; private set; }
public IRegistry Registry { get; private set; }
+
+ public IBrowser Browser { get; private set; }
}
}
diff --git a/src/OperatingSystemInfo.cs b/src/OperatingSystemInfo.cs
new file mode 100644
index 0000000..47deda5
--- /dev/null
+++ b/src/OperatingSystemInfo.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.Serialization;
+
+namespace Rothko
+{
+ ///
+ /// Represents information about an operating system, such as the version and platform identifier. This class
+ /// cannot be inherited.
+ ///
+ public sealed class OperatingSystemInfo : IOperatingSystemInfo
+ {
+ readonly OperatingSystem _operatingSystem;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public OperatingSystemInfo()
+ {
+ _operatingSystem = System.Environment.OSVersion;
+ }
+
+ ///
+ /// Creates an object that is identical to this instance.
+ ///
+ ///
+ public object Clone()
+ {
+ return _operatingSystem.Clone();
+ }
+
+ ///
+ /// Populates a object with the data necessary to
+ /// deserialize this instance.
+ ///
+ /// The object to populate with serialization information.
+ /// The place to store and retrieve serialized data. Reserved for future use.
+ /// info is null.
+ public void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ _operatingSystem.GetObjectData(info, context);
+ }
+
+ ///
+ /// Gets a enumeration value that identifies the operating system platform.
+ ///
+ public PlatformID Platform
+ {
+ get { return _operatingSystem.Platform; }
+ }
+
+ ///
+ /// Gets the service pack version represented by this OperatingSystem object.
+ ///
+ public string ServicePack
+ {
+ get { return _operatingSystem.ServicePack; }
+ }
+
+ ///
+ /// Gets a object that identifies the operating system.
+ ///
+ ///
+ /// For this to work properly for Windows 8.1 and later, be sure to specify the supported operating systems
+ /// https://msdn.microsoft.com/en-us/library/windows/desktop/dn481241(v=vs.85).aspx
+ ///
+ public Version Version
+ {
+ get { return _operatingSystem.Version; }
+ }
+
+ ///
+ /// Gets the concatenated string representation of the platform identifier, version, and service pack that are
+ /// currently installed on the operating system.
+ ///
+ public string VersionString
+ {
+ get { return _operatingSystem.VersionString; }
+ }
+
+ ///
+ /// Converts the value of this object to its equivalent string representation.
+ ///
+ /// The commercial name of the running operating system.
+ [SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations"
+ , Justification="We're following the contract of the base implementation here for better or worse.")]
+ public override string ToString()
+ {
+ return _operatingSystem.ToString();
+ }
+ }
+}
diff --git a/src/Processes/IProcess.cs b/src/Processes/IProcess.cs
index 8b2392c..18f68a9 100644
--- a/src/Processes/IProcess.cs
+++ b/src/Processes/IProcess.cs
@@ -17,6 +17,9 @@ public interface IProcess : IDisposable
int Id { get; }
ProcessStartInfo StartInfo { get; set; }
StreamWriter StandardInput { get; }
+ StreamReader StandardOutput { get; }
+ StreamReader StandardError { get; }
+
int ExitCode { get; }
IntPtr MainWindowHandle { get; }
string ProcessName { get; }
diff --git a/src/Processes/IProcessStarter.cs b/src/Processes/IProcessStarter.cs
index 0a0f35a..bf3103f 100644
--- a/src/Processes/IProcessStarter.cs
+++ b/src/Processes/IProcessStarter.cs
@@ -5,7 +5,19 @@ namespace Rothko
// You can use this instead of calling the static Process.Start directly.
public interface IProcessStarter
{
+ ///
+ /// Start a process with the given start info.
+ ///
+ /// Information about the process - like what arguments to pass etc
+ /// A instance.
IProcess Start(ProcessStartInfo processStartInfo);
+
+ ///
+ /// Starts a process
+ ///
+ /// The executable path
+ /// The arguments to pass
+ /// A instance.
IProcess Start(string fileName, string arguments);
}
}
\ No newline at end of file
diff --git a/src/Processes/NullProcess.cs b/src/Processes/NullProcess.cs
index 8eaa3ee..dd54f0c 100644
--- a/src/Processes/NullProcess.cs
+++ b/src/Processes/NullProcess.cs
@@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
using System.IO;
+using NullGuard;
namespace Rothko
{
@@ -22,14 +23,38 @@ public NullProcess()
public int Id { get { return 4; } }
- public ProcessStartInfo StartInfo { get; set; }
+ public ProcessStartInfo StartInfo
+ {
+ [return: AllowNull]
+ get; set;
+ }
+
+ public StreamWriter StandardInput
+ {
+ [return: AllowNull]
+ get { return null; }
+ }
+
+ public StreamReader StandardOutput
+ {
+ [return: AllowNull]
+ get { return null; }
+ }
- public StreamWriter StandardInput { get { return null; } }
+ public StreamReader StandardError
+ {
+ [return: AllowNull]
+ get { return null; }
+ }
public int ExitCode { get { return 0; } }
public IntPtr MainWindowHandle { get { return IntPtr.Zero; } }
- public string ProcessName { get { return null; } }
+ public string ProcessName
+ {
+ [return: AllowNull]
+ get { return null; }
+ }
public void BeginOutputReadLine()
{
diff --git a/src/Processes/ProcessWrapper.cs b/src/Processes/ProcessWrapper.cs
index 29a5dbc..c481599 100644
--- a/src/Processes/ProcessWrapper.cs
+++ b/src/Processes/ProcessWrapper.cs
@@ -6,6 +6,7 @@
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
+using System.Threading;
namespace Rothko
{
@@ -16,6 +17,7 @@ namespace Rothko
public class ProcessWrapper : IProcess
{
readonly Process process;
+ readonly SafeDisposable processDisposer;
public ProcessWrapper(ProcessStartInfo startInfo)
: this(startInfo, false)
@@ -42,6 +44,7 @@ protected ProcessWrapper(Process process, bool startImmediately)
this.process = process;
process.OutputDataReceived += OnOutputDataReceived;
process.ErrorDataReceived += OnErrorDataReceived;
+ processDisposer = new SafeDisposable(process);
if (startImmediately)
{
@@ -106,6 +109,9 @@ public StreamWriter StandardInput
get { return process.StandardInput; }
}
+ public StreamReader StandardOutput { get { return process.StandardOutput; } }
+ public StreamReader StandardError { get { return process.StandardOutput; } }
+
public int ExitCode
{
get { return process.ExitCode; }
@@ -180,9 +186,7 @@ protected virtual void Dispose(bool disposing)
{
if (disposing)
{
- var proc = process;
- if (proc != null)
- proc.Dispose();
+ processDisposer.Dispose();
}
}
@@ -255,5 +259,29 @@ static Process GetParentProcess(IntPtr handle)
return null;
}
}
+
+ // Use this when the reference must only be disposed once
+ sealed class SafeDisposable : IDisposable
+ {
+ int disposed;
+ readonly IDisposable disposable;
+
+ public SafeDisposable(IDisposable disposable)
+ {
+ this.disposable = disposable;
+ }
+
+ public void Dispose()
+ {
+ // Ensures this can only be called once.
+ if (Interlocked.CompareExchange(ref disposed, 1, 0) == 0)
+ {
+ // We also know disposable cannot be null here,
+ // even if the original reference is null.
+ disposable.Dispose();
+ }
+ }
+ }
+
}
}
diff --git a/src/Rothko.csproj b/src/Rothko.csproj
index 2c23100..5434a4c 100644
--- a/src/Rothko.csproj
+++ b/src/Rothko.csproj
@@ -12,8 +12,8 @@
Rothkov4.5512
- ..\packages\Fody.1.19.1.0
+ 45d821a1true
@@ -42,16 +42,22 @@
true..\Rothko.ruleset
+
+ true
+
+
+ key.snk
+
-
- ..\packages\NullGuard.Fody.1.0.0.0\Lib\portable-net4+sl4+wp7+win8+MonoAndroid16+MonoTouch40\NullGuard.dll
- ..\..\packages\NullGuard.Fody.1.1.0.0\Lib\portable-net4+sl4+wp7+win8+MonoAndroid16+MonoTouch40\NullGuard.dll
- ..\packages\NullGuard.Fody.1.1.0.0\Lib\portable-net4+sl4+wp7+win8+MonoAndroid16+MonoTouch40\NullGuard.dll
+
+ ..\packages\NullGuard.Fody.1.4.4\Lib\portable-net4+sl5+wpa81+wp8+win8+MonoAndroid16+MonoTouch40\NullGuard.dllFalse
+
+
@@ -70,28 +76,47 @@
+
+
+
-
+
+
-
-
+
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -111,7 +136,6 @@
-
@@ -125,11 +149,17 @@
-
+
-
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+ RELEASE_NOTES
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
BREAKING CHANGE: API for CreateAssemblyInfoWithConfig was set back to original version
+This resets the breaking change introduced in https://github.com/fsharp/FAKE/pull/471