diff --git a/Aspects/vm.Aspects.FtpTransfer/FileDescriptor.cs b/Aspects/FtpTransfer/FtpFileDescriptor.cs
similarity index 81%
rename from Aspects/vm.Aspects.FtpTransfer/FileDescriptor.cs
rename to Aspects/FtpTransfer/FtpFileDescriptor.cs
index 5b7f1ae..b6c3d82 100644
--- a/Aspects/vm.Aspects.FtpTransfer/FileDescriptor.cs
+++ b/Aspects/FtpTransfer/FtpFileDescriptor.cs
@@ -6,7 +6,7 @@ namespace vm.Aspects.FtpTransfer
/// Represents a file list entry in the list of file (Unix or DOS style) coming from the FTP site.
///
///
- public class FileListEntry : IEquatable
+ public class FtpFileListEntry : IEquatable
{
///
/// Gets or sets a value indicating whether this instance is folder or a file.
@@ -48,13 +48,13 @@ public class FileListEntry : IEquatable
///
public string Name { get; set; }
- #region IEquatable Members
+ #region IEquatable Members
///
/// Indicates whether the current object is equal to another object of the same type.
///
/// An object to compare with this object.
/// true if the current object is equal to the parameter; otherwise, false.
- public virtual bool Equals(FileListEntry other)
+ public virtual bool Equals(FtpFileListEntry other)
{
if (ReferenceEquals(other, null))
return false;
@@ -78,7 +78,7 @@ public virtual bool Equals(FileListEntry other)
/// The object to compare with the current object.
/// if the specified is equal to this instance; otherwise, .
public override bool Equals(object obj)
- => Equals(obj as FileListEntry);
+ => Equals(obj as FtpFileListEntry);
///
/// Returns a hash code for this instance.
@@ -89,45 +89,45 @@ public override int GetHashCode()
var hashCode = Constants.HashInitializer;
hashCode = Constants.HashMultiplier * hashCode + IsFolder.GetHashCode();
- hashCode = Constants.HashMultiplier * hashCode + AccessRights.GetHashCode();
+ hashCode = Constants.HashMultiplier * hashCode + (AccessRights!=null ? AccessRights.GetHashCode() : 0);
hashCode = Constants.HashMultiplier * hashCode + Number.GetHashCode();
- hashCode = Constants.HashMultiplier * hashCode + Owner.GetHashCode();
- hashCode = Constants.HashMultiplier * hashCode + Group.GetHashCode();
+ hashCode = Constants.HashMultiplier * hashCode + (Owner!=null ? Owner.GetHashCode() : 0);
+ hashCode = Constants.HashMultiplier * hashCode + (Group!=null ? Group.GetHashCode() : 0);
hashCode = Constants.HashMultiplier * hashCode + FileSize.GetHashCode();
hashCode = Constants.HashMultiplier * hashCode + Created.GetHashCode();
- hashCode = Constants.HashMultiplier * hashCode + Name.GetHashCode();
+ hashCode = Constants.HashMultiplier * hashCode + (Name!=null ? Name.GetHashCode() : 0);
return hashCode;
}
///
- /// Compares two objects.
+ /// Compares two objects.
///
/// The left operand.
/// The right operand.
///
- /// true if the objects are considered to be equal ();
+ /// true if the objects are considered to be equal ();
/// otherwise false.
///
public static bool operator ==(
- FileListEntry left,
- FileListEntry right)
+ FtpFileListEntry left,
+ FtpFileListEntry right)
=> ReferenceEquals(left, null)
? ReferenceEquals(right, null)
: left.Equals(right);
///
- /// Compares two objects.
+ /// Compares two objects.
///
/// The left operand.
/// The right operand.
///
- /// true if the objects are not considered to be equal ();
+ /// true if the objects are not considered to be equal ();
/// otherwise false.
///
public static bool operator !=(
- FileListEntry left,
- FileListEntry right)
+ FtpFileListEntry left,
+ FtpFileListEntry right)
=> !(left==right);
}
}
diff --git a/Aspects/vm.Aspects.FtpTransfer/FtpParseMSDosListStreams.cs b/Aspects/FtpTransfer/FtpParseMSDosListStreams.cs
similarity index 94%
rename from Aspects/vm.Aspects.FtpTransfer/FtpParseMSDosListStreams.cs
rename to Aspects/FtpTransfer/FtpParseMSDosListStreams.cs
index 9a679d0..48f1dab 100644
--- a/Aspects/vm.Aspects.FtpTransfer/FtpParseMSDosListStreams.cs
+++ b/Aspects/FtpTransfer/FtpParseMSDosListStreams.cs
@@ -32,10 +32,10 @@ public class FtpParseMSDosListStreams : IFileListParser
///
/// The list streams.
/// Sequence FileListEntry.
- public IEnumerable Parse(
+ public IEnumerable Parse(
Stream fileListStream)
{
- var reader = new StreamReader(fileListStream, Encoding.Unicode);
+ var reader = new StreamReader(fileListStream, Encoding.ASCII);
while (!reader.EndOfStream)
{
@@ -50,12 +50,12 @@ public IEnumerable Parse(
}
#endregion
- static FileListEntry StreamDescriptorFactory(Match match)
+ static FtpFileListEntry StreamDescriptorFactory(Match match)
{
int num;
DateTime dt;
- return new FileListEntry
+ return new FtpFileListEntry
{
IsFolder = !string.IsNullOrWhiteSpace(match.Groups["isDir"].Value),
Name = match.Groups["name"].Value,
diff --git a/Aspects/vm.Aspects.FtpTransfer/FtpParseUnixListStreams.cs b/Aspects/FtpTransfer/FtpParseUnixListStreams.cs
similarity index 90%
rename from Aspects/vm.Aspects.FtpTransfer/FtpParseUnixListStreams.cs
rename to Aspects/FtpTransfer/FtpParseUnixListStreams.cs
index 4f04ef8..f82dc8e 100644
--- a/Aspects/vm.Aspects.FtpTransfer/FtpParseUnixListStreams.cs
+++ b/Aspects/FtpTransfer/FtpParseUnixListStreams.cs
@@ -27,11 +27,11 @@ public class FtpParseUnixListStreams : IFileListParser
///
/// Parses the specified stream returned by the FTP site to the command ls or dir
- /// and produces a sequence of -s.
+ /// and produces a sequence of -s.
///
/// The stream whose contents will be parsed to produce the list of entries.
- /// A sequence of -s
- public IEnumerable Parse(
+ /// A sequence of -s
+ public IEnumerable Parse(
Stream fileListStream)
{
var reader = new StreamReader(fileListStream, Encoding.ASCII);
@@ -48,12 +48,12 @@ public IEnumerable Parse(
}
}
- static FileListEntry StreamDescriptorFactory(Match match)
+ static FtpFileListEntry StreamDescriptorFactory(Match match)
{
int num;
DateTime dt;
- return new FileListEntry
+ return new FtpFileListEntry
{
IsFolder = string.Compare(match.Groups["dir"].Value, "d", StringComparison.OrdinalIgnoreCase) == 0,
AccessRights = match.Groups["access"].Value,
diff --git a/Aspects/vm.Aspects.FtpTransfer/FtpUserCredentials.cs b/Aspects/FtpTransfer/FtpUserCredentials.cs
similarity index 59%
rename from Aspects/vm.Aspects.FtpTransfer/FtpUserCredentials.cs
rename to Aspects/FtpTransfer/FtpUserCredentials.cs
index 5e590a8..d2c043f 100644
--- a/Aspects/vm.Aspects.FtpTransfer/FtpUserCredentials.cs
+++ b/Aspects/FtpTransfer/FtpUserCredentials.cs
@@ -10,14 +10,7 @@ public class FtpUserCredentials
///
/// Needed in case the remote site requires user credentials.
/// The user name
- public virtual string UserName { get; set; }
-
- ///
- /// The encrypted password part of the credentials if required by the remote site.
- ///
- /// Needed in case the remote site requires user credentials.
- /// The encrypted password.
- public virtual string Password64 { get; set; }
+ public string UserName { get; set; }
///
/// Gets the password.
diff --git a/Aspects/vm.Aspects.FtpTransfer/IFileListParser.cs b/Aspects/FtpTransfer/IFileListParser.cs
similarity index 70%
rename from Aspects/vm.Aspects.FtpTransfer/IFileListParser.cs
rename to Aspects/FtpTransfer/IFileListParser.cs
index c168cff..2233c1f 100644
--- a/Aspects/vm.Aspects.FtpTransfer/IFileListParser.cs
+++ b/Aspects/FtpTransfer/IFileListParser.cs
@@ -13,21 +13,21 @@ public interface IFileListParser
{
///
/// Parses the specified stream returned by the FTP site to the command ls or dir
- /// and produces a sequence of -s.
+ /// and produces a sequence of -s.
///
/// The stream whose contents will be parsed to produce the list of entries.
- /// A sequence of -s
- IEnumerable Parse(Stream fileListStream);
+ /// A sequence of -s
+ IEnumerable Parse(Stream fileListStream);
}
#region IFileListParser contracts
[ContractClassFor(typeof(IFileListParser))]
abstract class IFileListParserContract : IFileListParser
{
- public IEnumerable Parse(Stream fileListStream)
+ public IEnumerable Parse(Stream fileListStream)
{
Contract.Requires(fileListStream != null, nameof(fileListStream));
- Contract.Ensures(Contract.Result>() != null);
+ Contract.Ensures(Contract.Result>() != null);
throw new NotImplementedException();
}
diff --git a/Aspects/FtpTransfer/ITransferClientConfiguration.cs b/Aspects/FtpTransfer/ITransferClientConfiguration.cs
new file mode 100644
index 0000000..5265d84
--- /dev/null
+++ b/Aspects/FtpTransfer/ITransferClientConfiguration.cs
@@ -0,0 +1,54 @@
+using System;
+
+namespace vm.Aspects.FtpTransfer
+{
+ ///
+ /// Represents the configuration properties of the FTP transfer site objects represented by .
+ /// Note that the interface inherits from which should be used by the transfer object to clone the properties internally for multiple use.
+ ///
+ ///
+ public interface ITransferClientConfiguration : ICloneable
+ {
+ #region Properties
+ ///
+ /// URL string of the target.
+ ///
+ /// This is the URL string of the resource to be downloaded (from) or uploaded (to)
+ /// The URL of the resource.
+ string Link { get; }
+
+ ///
+ /// Gets or sets a value that specifies that an SSL connection should be used.
+ ///
+ ///
+ /// true if SSL is enabled; otherwise, false.
+ ///
+ bool EnableSsl { get; }
+
+ ///
+ /// Gets or sets a value which specifies the data type for file transfers.
+ ///
+ bool UseBinary { get; }
+
+ ///
+ /// Gets or sets a value indicating whether the control connection to the FTP server is closed after the request completes.
+ ///
+ ///
+ /// true if keep-alive-s are enabled; otherwise, false.
+ ///
+ bool KeepAlive { get; }
+
+ ///
+ /// The user name part of the credentials if required by the remote site.
+ ///
+ /// Needed in case the remote site requires user credentials.
+ /// The user name
+ string UserName { get; }
+
+ ///
+ /// Gets the password.
+ ///
+ string Password { get; }
+ #endregion
+ }
+}
diff --git a/Aspects/vm.Aspects.FtpTransfer/ITransferFile.cs b/Aspects/FtpTransfer/ITransferFiles.cs
similarity index 96%
rename from Aspects/vm.Aspects.FtpTransfer/ITransferFile.cs
rename to Aspects/FtpTransfer/ITransferFiles.cs
index c783e0a..3b51367 100644
--- a/Aspects/vm.Aspects.FtpTransfer/ITransferFile.cs
+++ b/Aspects/FtpTransfer/ITransferFiles.cs
@@ -9,10 +9,9 @@ namespace vm.Aspects.FtpTransfer
///
/// Abstracts a object that can list download and upload files (e.g. from an FTP site).
///
- [ContractClass(typeof(ITransferFileContract))]
- public interface ITransferFile
+ [ContractClass(typeof(ITransferFilesContract))]
+ public interface ITransferFiles
{
-
///
/// Lists the files available for receiving at the target (something like dir or ls).
///
@@ -35,7 +34,6 @@ public interface ITransferFile
// -----------------------------------------
-
///
/// Asynchronously lists the files available for receiving at the target (something like dir or ls).
///
@@ -59,8 +57,8 @@ public interface ITransferFile
}
#region ITransferFile contract binding
- [ContractClassFor(typeof(ITransferFile))]
- abstract class ITransferFileContract : ITransferFile
+ [ContractClassFor(typeof(ITransferFiles))]
+ abstract class ITransferFilesContract : ITransferFiles
{
public Stream DownloadFile(string name)
{
diff --git a/Aspects/vm.Aspects.FtpTransfer/Properties/AssemblyInfo.cs b/Aspects/FtpTransfer/Properties/AssemblyInfo.cs
similarity index 83%
rename from Aspects/vm.Aspects.FtpTransfer/Properties/AssemblyInfo.cs
rename to Aspects/FtpTransfer/Properties/AssemblyInfo.cs
index bbd6423..c474810 100644
--- a/Aspects/vm.Aspects.FtpTransfer/Properties/AssemblyInfo.cs
+++ b/Aspects/FtpTransfer/Properties/AssemblyInfo.cs
@@ -2,9 +2,9 @@
[assembly: AssemblyTitle("vm.Aspects.FtpTransfer")]
[assembly: AssemblyDescription("A set of classes for FTP file transfer.")]
-[assembly: AssemblyVersion("1.0.67")]
-[assembly: AssemblyFileVersion("1.0.67")]
-[assembly: AssemblyInformationalVersion("1.0.67")]
+[assembly: AssemblyVersion("1.0.68")]
+[assembly: AssemblyFileVersion("1.0.68")]
+[assembly: AssemblyInformationalVersion("1.0.68")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(
"vm.Aspects.FtpTransfer.Test, " +
diff --git a/Aspects/vm.Aspects.FtpTransfer/TransferSite.cs b/Aspects/FtpTransfer/TransferClient.cs
similarity index 59%
rename from Aspects/vm.Aspects.FtpTransfer/TransferSite.cs
rename to Aspects/FtpTransfer/TransferClient.cs
index 10fd006..43515b8 100644
--- a/Aspects/vm.Aspects.FtpTransfer/TransferSite.cs
+++ b/Aspects/FtpTransfer/TransferClient.cs
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
+using System.Diagnostics.Contracts;
using System.IO;
using System.Net;
using System.Net.Security;
@@ -14,121 +15,45 @@ namespace vm.Aspects.FtpTransfer
///
/// Represents an FTP site.
///
- ///
- public class TransferSite : ITransferFile
+ ///
+ public class TransferClient : ITransferFiles
{
#region Properties
///
- /// URL string of the target.
+ /// Gets the FTP configuration.
///
- /// This is the URL string of the resource to be downloaded (from) or uploaded (to)
- /// The URL of the resource.
- public string Link { get; set; }
+ ITransferClientConfiguration Configuration { get; }
///
- /// Gets or sets the enum value of the property TransmissionDirection.
+ /// Gets the client certificate identifying this owner to the FTP server.
///
- public TransmissionDirection TransmissionDirection { get; set; }
-
- ///
- /// Gets or sets the status code from the last transfer operation.
- ///
- ///
- /// The status code.
- ///
- public int StatusCode { get; set; }
-
- ///
- /// Gets or sets the status description from the FTP operation.
- ///
- ///
- /// The status code.
- ///
- public string StatusDescription { get; set; }
-
- ///
- /// Gets or sets the name of the list parser for this (inbound) site which will parse the text list of available streams for download to a list of objects.
- ///
- ///
- /// The name of the list parser.
- ///
- public string ListParser { get; set; }
-
- ///
- /// Gets or sets the credentials which might be needed at the target site.
- ///
- ///
- /// The credentials.
- ///
- public FtpUserCredentials Credentials { get; set; }
-
- ///
- /// Gets or sets the data by which to find the corresponding client certificate in the Windows certificate stores.
- ///
- ///
- /// The certificate data.
- ///
- public CertificateData ClientCertificate { get; set; }
-
- ///
- /// Gets or sets a value indicating whether the control connection to the FTP server is closed after the request completes.
- ///
- ///
- /// true if keep-alive-s are enabled; otherwise, false.
- ///
- public bool KeepAlive { get; set; }
-
- ///
- /// Gets or sets a value that specifies that an SSL connection should be used.
- ///
- ///
- /// true if SSL is enabled; otherwise, false.
- ///
- public bool EnableSsl { get; set; }
-
- ///
- /// Gets or sets a value which specifies the data type for file transfers.
- ///
- public bool UseBinary { get; set; }
+ X509Certificate2 ClientCertificate { get; }
#endregion
///
- /// Callback to validate a server certificate.
+ /// Initializes a new instance of the class.
///
- ///
- /// The default implementation here allows for self-signed certificate within the intranet and
- /// the local computer otherwise it fails if the server certificate is not kosher.
- ///
- bool ServerCertificateValidation(
- object sender,
- X509Certificate certificate,
- X509Chain chain,
- SslPolicyErrors sslPolicyErrors)
+ /// The FTP client configuration.
+ /// The FTP client certificate.
+ public TransferClient(
+ ITransferClientConfiguration configuration,
+ X509Certificate2 clientCertificate = null)
{
- if (sslPolicyErrors == SslPolicyErrors.None)
- return true;
-
- if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors) ||
- sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch))
- {
- // allow self-signed certificates
- Zone z = Zone.CreateFromUrl(((WebRequest)sender).RequestUri.ToString());
+ Contract.Requires(configuration != null, nameof(configuration));
- if (z.SecurityZone == SecurityZone.Intranet ||
- z.SecurityZone == SecurityZone.MyComputer)
- return true;
- }
-
- return false;
+ Configuration = (ITransferClientConfiguration)configuration.Clone();
+ ClientCertificate = clientCertificate;
}
+ // ---------------------------------------------------------------------------
+
///
/// Lists the files available for receiving at the target (something like dir).
///
/// The stream that will receive the files list text. The interpretation of the list text is up to the consumer.
public Stream ListFiles()
{
- var request = PrepareFileRequest(WebRequestMethods.Ftp.ListDirectoryDetails, null);
+ var request = PrepareFileRequest(WebRequestMethods.Ftp.ListDirectoryDetails, null);
var response = request.GetResponse();
return response.GetResponseStream();
@@ -141,7 +66,7 @@ public Stream ListFiles()
/// Task{Stream}.
public Stream DownloadFile(string name)
{
- var request = PrepareFileRequest(WebRequestMethods.Ftp.DownloadFile, name);
+ var request = PrepareFileRequest(WebRequestMethods.Ftp.DownloadFile, name);
var response = request.GetResponse();
return response.GetResponseStream();
@@ -156,9 +81,12 @@ public Stream DownloadFile(string name)
public void UploadFile(Stream stream, string name)
{
var request = PrepareFileRequest(WebRequestMethods.Ftp.UploadFile, name);
- var targetStream = request.GetRequestStream();
- stream.CopyTo(targetStream);
+ using (var requestStream = request.GetRequestStream())
+ stream.CopyTo(requestStream);
+
+ using (var response = request.GetResponse())
+ response.Close();
}
// ---------------------------------------------------------------------------
@@ -169,7 +97,7 @@ public void UploadFile(Stream stream, string name)
/// The stream that will receive the files list text. The interpretation of the list text is up to the consumer.
public async Task ListFilesAsync()
{
- var request = PrepareFileRequest(WebRequestMethods.Ftp.ListDirectoryDetails, null);
+ var request = PrepareFileRequest(WebRequestMethods.Ftp.ListDirectoryDetails, null);
var response = await request.GetResponseAsync();
return response.GetResponseStream();
@@ -182,7 +110,7 @@ public async Task ListFilesAsync()
/// Task{Stream}.
public async Task DownloadFileAsync(string name)
{
- var request = PrepareFileRequest(WebRequestMethods.Ftp.DownloadFile, name);
+ var request = PrepareFileRequest(WebRequestMethods.Ftp.DownloadFile, name);
var response = await request.GetResponseAsync();
return response.GetResponseStream();
@@ -197,11 +125,15 @@ public async Task DownloadFileAsync(string name)
public async Task UploadFileAsync(Stream stream, string name)
{
var request = PrepareFileRequest(WebRequestMethods.Ftp.UploadFile, name);
- var targetStream = await request.GetRequestStreamAsync();
- await stream.CopyToAsync(targetStream);
+ using (var requestStream = await request.GetRequestStreamAsync())
+ await stream.CopyToAsync(requestStream);
+
+ using (var response = await request.GetResponseAsync())
+ response.Close();
}
+ // ---------------------------------------------------------------------------
///
/// Prepares the FTP request. After calling this the only thing that will be needed will be the FTP method.
@@ -215,7 +147,7 @@ FtpWebRequest PrepareFileRequest(
string method,
string fileName)
{
- var fileUrl = Link;
+ var fileUrl = Configuration.Link;
if (!string.IsNullOrWhiteSpace(fileName))
{
@@ -236,25 +168,52 @@ FtpWebRequest PrepareFileRequest(
Debug.Assert(request != null);
request.Method = method;
- request.UseBinary = UseBinary;
- request.KeepAlive = KeepAlive;
- request.EnableSsl = EnableSsl;
+ request.UseBinary = Configuration.UseBinary;
+ request.KeepAlive = Configuration.KeepAlive;
+ request.EnableSsl = Configuration.EnableSsl;
- if (EnableSsl)
+ if (Configuration.EnableSsl)
ServicePointManager.ServerCertificateValidationCallback = ServerCertificateValidation;
- if (Credentials != null &&
- !string.IsNullOrWhiteSpace(Credentials.UserName))
+ if (!string.IsNullOrWhiteSpace(Configuration.UserName))
request.Credentials = new NetworkCredential(
- Credentials.UserName,
- Credentials.Password);
-
- var clientCertificate = ClientCertificate?.Certificate;
+ Configuration.UserName,
+ Configuration.Password);
- if (clientCertificate != null)
- request.ClientCertificates.Add(clientCertificate);
+ if (ClientCertificate != null)
+ request.ClientCertificates.Add(ClientCertificate);
return request;
}
+
+ ///
+ /// Callback to validate a server certificate.
+ ///
+ ///
+ /// The default implementation here allows for self-signed certificate within the intranet and
+ /// the local computer otherwise it fails if the server certificate is not kosher.
+ ///
+ bool ServerCertificateValidation(
+ object sender,
+ X509Certificate serverCertificate,
+ X509Chain chain,
+ SslPolicyErrors sslPolicyErrors)
+ {
+ if (sslPolicyErrors == SslPolicyErrors.None)
+ return true;
+
+ if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors) ||
+ sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch))
+ {
+ // allow self-signed certificates
+ var z = Zone.CreateFromUrl(((WebRequest)sender).RequestUri.ToString());
+
+ if (z.SecurityZone == SecurityZone.Intranet ||
+ z.SecurityZone == SecurityZone.MyComputer)
+ return true;
+ }
+
+ return false;
+ }
}
}
diff --git a/Aspects/FtpTransfer/TransferClientConfiguration.cs b/Aspects/FtpTransfer/TransferClientConfiguration.cs
new file mode 100644
index 0000000..fa93854
--- /dev/null
+++ b/Aspects/FtpTransfer/TransferClientConfiguration.cs
@@ -0,0 +1,58 @@
+using System;
+
+namespace vm.Aspects.FtpTransfer
+{
+ ///
+ /// Class TransferClientConfiguration.
+ ///
+ ///
+ public class TransferClientConfiguration : ITransferClientConfiguration
+ {
+ ///
+ /// URL string of the target.
+ ///
+ /// This is the URL string of the resource to be downloaded (from) or uploaded (to)
+ public string Link { get; set; }
+
+ ///
+ /// Gets or sets a value that specifies that an SSL connection should be used.
+ ///
+ public bool EnableSsl { get; set; }
+
+ ///
+ /// Gets or sets a value which specifies the data type for file transfers.
+ ///
+ public bool UseBinary { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the control connection to the FTP server is closed after the request completes.
+ ///
+ public bool KeepAlive { get; set; }
+
+ ///
+ /// The user name part of the credentials if required by the remote site.
+ ///
+ /// Needed in case the remote site requires user credentials.
+ public string UserName { get; set; }
+
+ ///
+ /// Gets the password.
+ ///
+ public string Password { get; set; }
+
+ ///
+ /// Creates a new object that is a copy of the current instance.
+ ///
+ /// A new object that is a copy of this instance.
+ public object Clone()
+ => new TransferClientConfiguration
+ {
+ Link = Link,
+ EnableSsl = EnableSsl,
+ UseBinary = UseBinary,
+ KeepAlive = KeepAlive,
+ UserName = UserName,
+ Password = Password,
+ };
+ }
+}
diff --git a/Aspects/vm.Aspects.FtpTransfer/vm.Aspects.FtpTransfer.csproj b/Aspects/FtpTransfer/vm.Aspects.FtpTransfer.csproj
similarity index 96%
rename from Aspects/vm.Aspects.FtpTransfer/vm.Aspects.FtpTransfer.csproj
rename to Aspects/FtpTransfer/vm.Aspects.FtpTransfer.csproj
index 03cb21a..3f17d75 100644
--- a/Aspects/vm.Aspects.FtpTransfer/vm.Aspects.FtpTransfer.csproj
+++ b/Aspects/FtpTransfer/vm.Aspects.FtpTransfer.csproj
@@ -119,6 +119,7 @@
ReleaseRequires%28none%290
+ bin\Release\vm.Aspects.FtpTransfer.XMLtrue
@@ -140,16 +141,16 @@
Properties\AssemblyInfo.global.cs
-
-
+
-
+
+
-
-
+
+
diff --git a/Aspects/Linq/Expressions/Serialization/NuGet/ExpressionSerialization.nuspec b/Aspects/Linq/Expressions/Serialization/NuGet/ExpressionSerialization.nuspec
index 3ee64c0..c22cd0d 100644
--- a/Aspects/Linq/Expressions/Serialization/NuGet/ExpressionSerialization.nuspec
+++ b/Aspects/Linq/Expressions/Serialization/NuGet/ExpressionSerialization.nuspec
@@ -2,7 +2,7 @@
AspectExpressionSerialization
- 1.0.67
+ 1.0.68Val MelamedVal Melamed
diff --git a/Aspects/Linq/Expressions/Serialization/Properties/AssemblyInfo.cs b/Aspects/Linq/Expressions/Serialization/Properties/AssemblyInfo.cs
index e4a7f59..2a8a267 100644
--- a/Aspects/Linq/Expressions/Serialization/Properties/AssemblyInfo.cs
+++ b/Aspects/Linq/Expressions/Serialization/Properties/AssemblyInfo.cs
@@ -4,9 +4,9 @@
[assembly: AssemblyTitle("vm.Aspects.Linq.Expressions.Serialization")]
[assembly: AssemblyDescription("Serializes and deserializes LINQ expression trees to and from XML documents.")]
-[assembly: AssemblyVersion("1.0.67")]
-[assembly: AssemblyFileVersion("1.0.67")]
-[assembly: AssemblyInformationalVersion("1.0.67")]
+[assembly: AssemblyVersion("1.0.68")]
+[assembly: AssemblyFileVersion("1.0.68")]
+[assembly: AssemblyInformationalVersion("1.0.68")]
[assembly: InternalsVisibleTo(
"vm.Aspects.Linq.Expressions.Serialization.Test, " +
diff --git a/Aspects/Model/Properties/AssemblyInfo.cs b/Aspects/Model/Properties/AssemblyInfo.cs
index e2ef9ed..1a9f0bf 100644
--- a/Aspects/Model/Properties/AssemblyInfo.cs
+++ b/Aspects/Model/Properties/AssemblyInfo.cs
@@ -3,9 +3,9 @@
[assembly: AssemblyTitle("vm.Aspect.Model")]
[assembly: AssemblyDescription("Defines the IRepository and related base classes and utilities - a framework of building domain object model.")]
-[assembly: AssemblyVersion("1.0.67")]
-[assembly: AssemblyFileVersion("1.0.67")]
-[assembly: AssemblyInformationalVersion("1.0.67")]
+[assembly: AssemblyVersion("1.0.68")]
+[assembly: AssemblyFileVersion("1.0.68")]
+[assembly: AssemblyInformationalVersion("1.0.68")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(
"vm.Aspects.Model.Tests, " +
diff --git a/Aspects/NuGet/PublishAspects.cmd b/Aspects/NuGet/PublishAspects.cmd
index d2943b8..ff2dbf5 100644
--- a/Aspects/NuGet/PublishAspects.cmd
+++ b/Aspects/NuGet/PublishAspects.cmd
@@ -1,6 +1,6 @@
if "%VSINSTALLDIR%"=="" call "%VS140COMNTOOLS%vsvars32.bat"
set Configuration=Release
-set vmAspectsVersion=1.0.67-beta
+set vmAspectsVersion=1.0.68-beta
pushd
cd %~dp0..
@@ -21,6 +21,9 @@ if errorlevel 1 goto exit
cd ..\Parsers
msbuild vm.Aspects.Parsers.csproj %commonBuildOptions%
if errorlevel 1 goto exit
+cd ..\FtpTransfer
+msbuild vm.Aspects.FtpTransfer.csproj %commonBuildOptions%
+if errorlevel 1 goto exit
cd ..\Wcf
msbuild vm.Aspects.Wcf.csproj %commonBuildOptions%
if errorlevel 1 goto exit
diff --git a/Aspects/NuGet/vm.Aspects.nuspec b/Aspects/NuGet/vm.Aspects.nuspec
index e3de352..2c704f4 100644
--- a/Aspects/NuGet/vm.Aspects.nuspec
+++ b/Aspects/NuGet/vm.Aspects.nuspec
@@ -2,7 +2,7 @@
vm.Aspects
- 1.0.67-beta
+ 1.0.68-betaVal MelamedVal Melamed
@@ -12,7 +12,7 @@
A set of classes, utilities, etc. addressing various common cross-cutting concerns or extending existing similar libraries like Enterprise Library, Unity, etc.
- * Targeting the .NET 4.5.2
+ * Added a project with a few classes for FTP transfer.
https://github.com/vmelamed/vm/blob/master/LICENSEhttps://github.com/vmelamed/vm/tree/master/Aspects
@@ -68,6 +68,10 @@
target="lib\net452"/>
+
+
public virtual IHasherAsync ReleaseCertificate()
{
- Contract.Ensures(Contract.Result() != null);
+ Contract.Ensures(Contract.Result() != null);
if (_publicKey == null)
return this;
@@ -593,7 +593,7 @@ public virtual IHasherAsync ReleaseCertificate()
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "The caller owns it.")]
public virtual IHasherAsync CloneLightHasher()
{
- Contract.Ensures(Contract.Result() != null);
+ Contract.Ensures(Contract.Result() != null);
InitializeHashKey();
diff --git a/Aspects/Test/TestFtpClient/App.config b/Aspects/Test/TestFtpClient/App.config
index 731f6de..8227adb 100644
--- a/Aspects/Test/TestFtpClient/App.config
+++ b/Aspects/Test/TestFtpClient/App.config
@@ -1,6 +1,6 @@
-
+
-
+
-
\ No newline at end of file
+
diff --git a/Aspects/Test/TestFtpClient/Program.cs b/Aspects/Test/TestFtpClient/Program.cs
index fb1c317..63b9878 100644
--- a/Aspects/Test/TestFtpClient/Program.cs
+++ b/Aspects/Test/TestFtpClient/Program.cs
@@ -1,7 +1,7 @@
using System;
using System.Diagnostics;
using System.IO;
-using System.Security.Cryptography.X509Certificates;
+using System.Linq;
using vm.Aspects;
using vm.Aspects.FtpTransfer;
@@ -13,28 +13,61 @@ static void Main(string[] args)
{
try
{
- var site = new TransferSite
+ var config = new TransferClientConfiguration
{
- Link = "ftp://ftp.testalmond.net",
- EnableSsl = true,
- UseBinary = true,
- TransmissionDirection = TransmissionDirection.Inbound,
- ClientCertificate = new CertificateData
- {
- StoreLocation = StoreLocation.LocalMachine,
- StoreName = StoreName.My,
- FindBy = X509FindType.FindByThumbprint,
- FindByValue = "8114d495c16247dac51c586af91eb0d42c2d1ccf",
- },
- Credentials = new FtpUserCredentials
- {
- UserName = "val",
- Password = "Almond123"
- },
+ EnableSsl = true,
+ UseBinary = true,
+ UserName = "user",
+ Password = "password",
};
- using (var rdr = new StreamReader(site.ListFiles()))
- Console.WriteLine(rdr.ReadToEnd());
+ config.Link = "ftp://localhost/outgoing";
+
+ var site1 = new TransferClient(config);
+
+ config.Link = "ftp://localhost/incoming";
+
+ var site2 = new TransferClient(config);
+
+ var files = new FtpParseMSDosListStreams()
+ .Parse(site1.ListFiles())
+ .Take(4)
+ .ToList()
+ ;
+ var file1 = files[0];
+ var file2 = files[1];
+ var file3 = files[2];
+ var file4 = files[3];
+
+ // download to file from site1 to a local file and then upload it to site2
+ using (var fileStream = new FileStream(file1.Name, FileMode.Create, FileAccess.Write, FileShare.None))
+ using (var outStream = site1.DownloadFile(file1.Name))
+ outStream.CopyTo(fileStream);
+
+ using (var fileStream = new FileStream(file1.Name, FileMode.Open, FileAccess.Read, FileShare.None))
+ site2.UploadFile(fileStream, file1.Name);
+
+ // ----------------------------------------------------------
+
+ // download from site1 and then upload it to site2 w/o intermediate local file
+ using (var outStream = site1.DownloadFile(file2.Name))
+ site2.UploadFile(outStream, file2.Name);
+
+ // ----------------------------------------------------------
+
+ // async download to file from site1 to a local file and then async upload it to site2
+ using (var fileStream = new FileStream(file3.Name, FileMode.Create, FileAccess.Write, FileShare.None))
+ using (var outStream = site1.DownloadFileAsync(file3.Name).Result)
+ outStream.CopyTo(fileStream);
+
+ using (var fileStream = new FileStream(file3.Name, FileMode.Open, FileAccess.Read, FileShare.None))
+ site2.UploadFileAsync(fileStream, file3.Name).GetAwaiter().GetResult();
+
+ // ----------------------------------------------------------
+
+ // download from site1 and then upload it to site2 w/o intermediate local file
+ using (var outStream = site1.DownloadFileAsync(file4.Name).Result)
+ site2.UploadFileAsync(outStream, file4.Name).GetAwaiter().GetResult();
}
catch (Exception x)
{
diff --git a/Aspects/Test/TestFtpClient/TestFtpClient.csproj b/Aspects/Test/TestFtpClient/TestFtpClient.csproj
index 937410e..a06a429 100644
--- a/Aspects/Test/TestFtpClient/TestFtpClient.csproj
+++ b/Aspects/Test/TestFtpClient/TestFtpClient.csproj
@@ -9,9 +9,10 @@
PropertiesTestFtpClientTestFtpClient
- v4.6.1
+ v4.5.2512true
+ AnyCPU
@@ -54,7 +55,7 @@
{372A2FEF-C004-498C-B57F-CF0ACA66C37B}vm.Aspects.Diagnostics.ObjectDumper
-
+ {113ce397-4859-4b92-8f10-e5ba2d6f1a35}vm.Aspects.FtpTransfer
diff --git a/Aspects/Wcf/Properties/AssemblyInfo.cs b/Aspects/Wcf/Properties/AssemblyInfo.cs
index 8c4a8c5..49bb978 100644
--- a/Aspects/Wcf/Properties/AssemblyInfo.cs
+++ b/Aspects/Wcf/Properties/AssemblyInfo.cs
@@ -3,9 +3,9 @@
[assembly: AssemblyTitle("Wcf")]
[assembly: AssemblyDescription("A set of classes and generics simplifying the initial configuration work of creating WCF services.")]
-[assembly: AssemblyVersion("1.0.67")]
-[assembly: AssemblyFileVersion("1.0.67")]
-[assembly: AssemblyInformationalVersion("1.0.67")]
+[assembly: AssemblyVersion("1.0.68")]
+[assembly: AssemblyFileVersion("1.0.68")]
+[assembly: AssemblyInformationalVersion("1.0.68")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(
"vm.Aspects.Wcf.Test, " +
diff --git a/Aspects/vm.Aspects.FtpTransfer/CertificateData.cs b/Aspects/vm.Aspects.FtpTransfer/CertificateData.cs
deleted file mode 100644
index 5afbdfb..0000000
--- a/Aspects/vm.Aspects.FtpTransfer/CertificateData.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using System.Security.Cryptography.X509Certificates;
-using vm.Aspects.Security;
-
-namespace vm.Aspects.FtpTransfer
-{
- ///
- /// Encapsulates the data by which to find a certificate in the Windows certificate stores.
- ///
- public class CertificateData
- {
- ///
- /// In case the remote site uses client certificates this property identifies the store location where the client certificate is.
- ///
- /// The store location where the store with the client certificate should be found.
- public StoreLocation StoreLocation { get; set; }
-
- ///
- /// In case the remote site uses client certificates this property identifies the store where the client certificate is.
- ///
- /// The store where the client certificate should be found.
- public StoreName StoreName { get; set; }
-
- ///
- /// Gets or sets the part by which the certificate can be found in the store.
- ///
- ///
- /// The field by which the certificate can be found in the store.
- ///
- ///
- /// When extracting the certificate the property always combines this criterion with
- /// and the current time, so specifying this value as well as the other time related criteria
- /// does not make sense.
- ///
- public X509FindType FindBy { get; set; }
-
- ///
- /// Gets or sets the certificate field value by which it can be found in the store.
- ///
- ///
- /// The certificate field value by which it can be found in the store.
- ///
- public string FindByValue { get; set; }
-
- ///
- /// Extracts the first 509 certificate from the Windows certificate stores which matches the and combined with
- /// and the current date and time.
- ///
- ///
- /// The 509 certificate or null if the instance does not specify certificate, e.g. all fields are null.
- ///
- public X509Certificate2 Certificate
- => CertificateFactory.GetCertificate(StoreLocation, StoreName, FindBy, FindByValue);
- }
-}
diff --git a/Aspects/vm.Aspects.FtpTransfer/TransmissionDirection.cs b/Aspects/vm.Aspects.FtpTransfer/TransmissionDirection.cs
deleted file mode 100644
index 0527a2c..0000000
--- a/Aspects/vm.Aspects.FtpTransfer/TransmissionDirection.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-namespace vm.Aspects.FtpTransfer
-{
- ///
- /// Specifies the file transfer direction.
- ///
- public enum TransmissionDirection
- {
- ///
- /// Unknown, uninitialized direction
- ///
- None,
-
- ///
- /// The file transfer is from the remote target to the intranet consumers.
- ///
- Inbound,
-
- ///
- /// The file transfer is from the intranet producers to the remote target.
- ///
- Outbound,
- }
-}
diff --git a/vm.Aspects.sln b/vm.Aspects.sln
index 5f21635..3573645 100644
--- a/vm.Aspects.sln
+++ b/vm.Aspects.sln
@@ -8,6 +8,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
Common Items\AssemblyInfo.global.cs = Common Items\AssemblyInfo.global.cs
Common Items\Dictionary.xml = Common Items\Dictionary.xml
+ Aspects\FtpTransfer\vm.Aspects.FtpTransfer.csproj = Aspects\FtpTransfer\vm.Aspects.FtpTransfer.csproj
Common Items\vm.snk = Common Items\vm.snk
Common Items\vm.Test.snk = Common Items\vm.Test.snk
Common Items\vmAllRules.ruleset = Common Items\vmAllRules.ruleset
@@ -66,10 +67,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileCrypt", "Aspects\Securi
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "vm.Aspects.Wcf.Tests", "Aspects\Wcf\Tests\vm.Aspects.Wcf.Tests.csproj", "{9F87B835-8270-42F9-9567-26B2C7489C2B}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "vm.Aspects.FtpTransfer", "Aspects\vm.Aspects.FtpTransfer\vm.Aspects.FtpTransfer.csproj", "{113CE397-4859-4B92-8F10-E5BA2D6F1A35}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestFtpClient", "Aspects\Test\TestFtpClient\TestFtpClient.csproj", "{73B4C51D-31EE-4DBC-B7E9-FA13FF817F1D}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "vm.Aspects.FtpTransfer", "Aspects\FtpTransfer\vm.Aspects.FtpTransfer.csproj", "{113CE397-4859-4B92-8F10-E5BA2D6F1A35}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -191,18 +192,18 @@ Global
{9F87B835-8270-42F9-9567-26B2C7489C2B}.DebugUnitTest|Any CPU.Build.0 = Debug|Any CPU
{9F87B835-8270-42F9-9567-26B2C7489C2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9F87B835-8270-42F9-9567-26B2C7489C2B}.Release|Any CPU.Build.0 = Release|Any CPU
- {113CE397-4859-4B92-8F10-E5BA2D6F1A35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {113CE397-4859-4B92-8F10-E5BA2D6F1A35}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {113CE397-4859-4B92-8F10-E5BA2D6F1A35}.DebugUnitTest|Any CPU.ActiveCfg = Debug|Any CPU
- {113CE397-4859-4B92-8F10-E5BA2D6F1A35}.DebugUnitTest|Any CPU.Build.0 = Debug|Any CPU
- {113CE397-4859-4B92-8F10-E5BA2D6F1A35}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {113CE397-4859-4B92-8F10-E5BA2D6F1A35}.Release|Any CPU.Build.0 = Release|Any CPU
{73B4C51D-31EE-4DBC-B7E9-FA13FF817F1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{73B4C51D-31EE-4DBC-B7E9-FA13FF817F1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{73B4C51D-31EE-4DBC-B7E9-FA13FF817F1D}.DebugUnitTest|Any CPU.ActiveCfg = Debug|Any CPU
{73B4C51D-31EE-4DBC-B7E9-FA13FF817F1D}.DebugUnitTest|Any CPU.Build.0 = Debug|Any CPU
{73B4C51D-31EE-4DBC-B7E9-FA13FF817F1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{73B4C51D-31EE-4DBC-B7E9-FA13FF817F1D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {113CE397-4859-4B92-8F10-E5BA2D6F1A35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {113CE397-4859-4B92-8F10-E5BA2D6F1A35}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {113CE397-4859-4B92-8F10-E5BA2D6F1A35}.DebugUnitTest|Any CPU.ActiveCfg = Debug|Any CPU
+ {113CE397-4859-4B92-8F10-E5BA2D6F1A35}.DebugUnitTest|Any CPU.Build.0 = Debug|Any CPU
+ {113CE397-4859-4B92-8F10-E5BA2D6F1A35}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {113CE397-4859-4B92-8F10-E5BA2D6F1A35}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -223,7 +224,7 @@ Global
{73B4C51D-31EE-4DBC-B7E9-FA13FF817F1D} = {B2E493FE-EFCF-4D0B-84C5-5C75B0D361B8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
- EnterpriseLibraryConfigurationToolBinariesPathV6 = packages\EnterpriseLibrary.Common.6.0.1304.0\lib\NET45;packages\EnterpriseLibrary.Logging.6.0.1304.0\lib\NET45;packages\EnterpriseLibrary.ExceptionHandling.6.0.1304.0\lib\NET45;packages\EnterpriseLibrary.Validation.6.0.1304.0\lib\NET45;packages\EnterpriseLibrary.ExceptionHandling.Logging.6.0.1304.0\lib\NET45;packages\EnterpriseLibrary.PolicyInjection.6.0.1304.0\lib\NET45;packages\EnterpriseLibrary.ExceptionHandling.WCF.6.0.1304.0\lib\NET45;packages\EnterpriseLibrary.Validation.Integration.WCF.6.0.1304.0\lib\NET45
EnterpriseLibraryConfigurationToolBinariesPath = packages\EnterpriseLibrary.Common.5.0.505.0\lib\NET35;packages\EnterpriseLibrary.ExceptionHandling.5.0.505.0\lib\NET35;packages\EnterpriseLibrary.Logging.5.0.505.1\lib\NET35;packages\EnterpriseLibrary.ExceptionHandling.Logging.5.0.505.0\lib\NET35;packages\EnterpriseLibrary.PolicyInjection.5.0.505.0\lib\NET35;packages\EnterpriseLibrary.Validation.5.0.505.0\lib\NET35
+ EnterpriseLibraryConfigurationToolBinariesPathV6 = packages\EnterpriseLibrary.Common.6.0.1304.0\lib\NET45;packages\EnterpriseLibrary.Logging.6.0.1304.0\lib\NET45;packages\EnterpriseLibrary.ExceptionHandling.6.0.1304.0\lib\NET45;packages\EnterpriseLibrary.Validation.6.0.1304.0\lib\NET45;packages\EnterpriseLibrary.ExceptionHandling.Logging.6.0.1304.0\lib\NET45;packages\EnterpriseLibrary.PolicyInjection.6.0.1304.0\lib\NET45;packages\EnterpriseLibrary.ExceptionHandling.WCF.6.0.1304.0\lib\NET45;packages\EnterpriseLibrary.Validation.Integration.WCF.6.0.1304.0\lib\NET45
EndGlobalSection
EndGlobal