Related
I made a wrapper for the NATS Client which basically adds ASP.NET DI functionality. There are two "issues" that I think should be fixed.
I think _jetStream should be lazy loaded.
Lazy initialization is usually used whereby you only load or initialize an object when you first need it.
_jetStreamFactory = new Lazy<IJetStream>(() => connection.CreateJetStreamContext());
The library is meant to extend ConnectionFactory's capabilities with additional configuration options (Decorator pattern). Knowing that, I don't think it's appropriate to dependency inject IOptions<NatsProducerConfiguration> in the NatsPublisher class because it violates the main idea.
If there is anything else
The code that the question is about
public class ProducerConfiguration
{
public string[]? Servers { get; init; }
public string? Url { get; init; }
public string? User { get; init; }
public string? Password { get; init; }
public required string Stream { get; init; }
public required string Subject { get; init; }
}
public interface IPublisher
{
ValueTask<PublishAck> Publish<T>(T payload) where T : class;
ValueTask<PublishAck> PublishAsync(byte[] payload, IEnumerable<(string, string)> headers);
ValueTask<PublishAck> PublishWithDeduplicationIdAsync(byte[] payload, string id);
}
public sealed class NatsPublisher : IPublisher
{
private readonly ProducerConfiguration _configuration;
private readonly IJetStream _jetStream;
public NatsPublisher(IOptions<ProducerConfiguration> options, IConnection connection)
{
_configuration = options.Value;
JetStreamUtils.CreateStreamOrUpdateSubjects(connection, _configuration.Stream, _configuration.Subject);
_jetStream = connection.CreateJetStreamContext();
}
public async ValueTask<PublishAck> Publish<T>(T payload)
where T : class
{
var data = JsonSerializer.SerializeToUtf8Bytes(payload);
var msg = new Msg(_configuration.Subject, null, null, data);
return await _jetStream.PublishAsync(msg);
}
public async ValueTask<PublishAck> PublishAsync(byte[] payload)
{
var msg = new Msg(_configuration.Subject, null, null, payload);
return await _jetStream.PublishAsync(msg);
}
public async ValueTask<PublishAck> PublishAsync(byte[] payload, IEnumerable<(string, string)> headers)
{
var msg = new Msg(_configuration.Subject, null, null, payload);
foreach (var (header, val) in headers)
{
msg.Header[header] = val;
}
return await _jetStream.PublishAsync(msg);
}
public async ValueTask<PublishAck> PublishWithDeduplicationIdAsync(byte[] payload, string id)
{
var msg = new Msg(_configuration.Subject, null, null, payload)
{
Header = { ["Nats-Msg-Id"] = id }
};
return await _jetStream.PublishAsync(msg);
}
}
The library itself
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddNatsClient(
this IServiceCollection services,
Action<Options>? configureOptions = null,
ServiceLifetime connectionServiceLifeTime = ServiceLifetime.Transient)
{
ArgumentNullException.ThrowIfNull(services);
var defaultOptions = ConnectionFactory.GetDefaultOptions();
configureOptions?.Invoke(defaultOptions);
services.AddSingleton(defaultOptions);
services.AddSingleton<ConnectionFactory>();
services.AddSingleton<INatsClientConnectionFactory, NatsClientConnectionFactoryDecorator>();
services.TryAdd(new ServiceDescriptor(typeof(IConnection), provider =>
{
var options = provider.GetRequiredService<Options>();
var connectionFactory = provider.GetRequiredService<INatsClientConnectionFactory>();
return connectionFactory.CreateConnection(options);
}, connectionServiceLifeTime));
services.TryAdd(new ServiceDescriptor(typeof(IEncodedConnection), provider =>
{
var options = provider.GetRequiredService<Options>();
var connectionFactory = provider.GetRequiredService<INatsClientConnectionFactory>();
return connectionFactory.CreateEncodedConnection(options);
}, connectionServiceLifeTime));
return services;
}
}
public interface INatsClientConnectionFactory
{
IConnection CreateConnection(Action<Options>? configureOptions = null);
IConnection CreateConnection(Options options);
IEncodedConnection CreateEncodedConnection(Action<Options>? configureOptions = null);
IEncodedConnection CreateEncodedConnection(Options options);
}
public sealed class NatsClientConnectionFactoryDecorator : INatsClientConnectionFactory
{
private readonly ConnectionFactory _connectionFactory;
public NatsClientConnectionFactoryDecorator(ConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}
public IConnection CreateConnection(Action<Options>? configureOptions = default)
{
var options = ConnectionFactory.GetDefaultOptions();
configureOptions?.Invoke(options);
return CreateConnection(options);
}
public IConnection CreateConnection(Options options)
{
return _connectionFactory.CreateConnection(options);
}
public IEncodedConnection CreateEncodedConnection(Action<Options>? configureOptions = default)
{
var options = ConnectionFactory.GetDefaultOptions();
configureOptions?.Invoke(options);
return CreateEncodedConnection(options);
}
public IEncodedConnection CreateEncodedConnection(Options options)
{
return _connectionFactory.CreateEncodedConnection(options);
}
}
public static class JetStreamUtils
{
// ----------------------------------------------------------------------------------------------------
// STREAM INFO / CREATE / UPDATE
// ----------------------------------------------------------------------------------------------------
public static StreamInfo? GetStreamInfoOrNullWhenNotExist(IJetStreamManagement jsm, string streamName)
{
try
{
return jsm.GetStreamInfo(streamName);
}
catch (NATSJetStreamException e)
{
if (e.ErrorCode == 404)
{
return null;
}
throw;
}
}
public static bool StreamExists(IConnection c, string streamName)
{
return GetStreamInfoOrNullWhenNotExist(c.CreateJetStreamManagementContext(), streamName) != null;
}
public static bool StreamExists(IJetStreamManagement jsm, string streamName)
{
return GetStreamInfoOrNullWhenNotExist(jsm, streamName) != null;
}
public static void ExitIfStreamExists(IJetStreamManagement jsm, string streamName)
{
if (StreamExists(jsm, streamName))
{
Environment.Exit(-1);
}
}
public static void ExitIfStreamNotExists(IConnection c, string streamName)
{
if (!StreamExists(c, streamName))
{
Environment.Exit(-1);
}
}
public static StreamInfo CreateStream(IJetStreamManagement jsm, string streamName, StorageType storageType,
params string[] subjects)
{
var sc = StreamConfiguration.Builder()
.WithName(streamName)
.WithStorageType(storageType)
.WithSubjects(subjects)
.Build();
var si = jsm.AddStream(sc);
return si;
}
public static StreamInfo CreateStream(IJetStreamManagement jsm, string stream, params string[] subjects)
{
return CreateStream(jsm, stream, StorageType.Memory, subjects);
}
public static StreamInfo CreateStream(IConnection c, string stream, params string[] subjects)
{
return CreateStream(c.CreateJetStreamManagementContext(), stream, StorageType.Memory, subjects);
}
public static StreamInfo CreateStreamExitWhenExists(IConnection c, string streamName, params string[] subjects)
{
return CreateStreamExitWhenExists(c.CreateJetStreamManagementContext(), streamName, subjects);
}
public static StreamInfo CreateStreamExitWhenExists(IJetStreamManagement jsm, string streamName,
params string[] subjects)
{
ExitIfStreamExists(jsm, streamName);
return CreateStream(jsm, streamName, StorageType.Memory, subjects);
}
public static void CreateStreamWhenDoesNotExist(IJetStreamManagement jsm, string stream, params string[] subjects)
{
try
{
jsm.GetStreamInfo(stream);
return;
}
catch (NATSJetStreamException)
{
}
var sc = StreamConfiguration.Builder()
.WithName(stream)
.WithStorageType(StorageType.Memory)
.WithSubjects(subjects)
.Build();
jsm.AddStream(sc);
}
public static void CreateStreamWhenDoesNotExist(IConnection c, string stream, params string[] subjects)
{
CreateStreamWhenDoesNotExist(c.CreateJetStreamManagementContext(), stream, subjects);
}
public static StreamInfo CreateStreamOrUpdateSubjects(IJetStreamManagement jsm, string streamName,
StorageType storageType, params string[] subjects)
{
var si = GetStreamInfoOrNullWhenNotExist(jsm, streamName);
if (si == null)
{
return CreateStream(jsm, streamName, storageType, subjects);
}
var sc = si.Config;
var needToUpdate = false;
foreach (var sub in subjects)
{
if (!sc.Subjects.Contains(sub))
{
needToUpdate = true;
sc.Subjects.Add(sub);
}
}
if (needToUpdate)
{
si = jsm.UpdateStream(sc);
}
return si;
}
public static StreamInfo CreateStreamOrUpdateSubjects(IJetStreamManagement jsm, string streamName,
params string[] subjects)
{
return CreateStreamOrUpdateSubjects(jsm, streamName, StorageType.Memory, subjects);
}
public static StreamInfo CreateStreamOrUpdateSubjects(IConnection c, string stream, params string[] subjects)
{
return CreateStreamOrUpdateSubjects(c.CreateJetStreamManagementContext(), stream, StorageType.Memory,
subjects);
}
// ----------------------------------------------------------------------------------------------------
// PUBLISH
// ----------------------------------------------------------------------------------------------------
public static void Publish(IConnection c, string subject, int count)
{
Publish(c.CreateJetStreamContext(), subject, "data", count);
}
public static void Publish(IJetStream js, string subject, int count)
{
Publish(js, subject, "data", count);
}
public static void Publish(IJetStream js, string subject, string prefix, int count)
{
for (var x = 1; x <= count; x++)
{
var data = prefix + x;
js.Publish(subject, Encoding.UTF8.GetBytes(data));
}
}
public static void PublishInBackground(IJetStream js, string subject, string prefix, int count)
{
new Thread(() =>
{
try
{
for (var x = 1; x <= count; x++)
{
js.Publish(subject, Encoding.ASCII.GetBytes(prefix + "-" + x));
}
}
catch (Exception)
{
Environment.Exit(-1);
}
}).Start();
Thread.Sleep(100); // give the publish thread a little time to get going
}
// ----------------------------------------------------------------------------------------------------
// READ MESSAGES
// ----------------------------------------------------------------------------------------------------
public static IList<Msg> ReadMessagesAck(ISyncSubscription sub, int timeout = 1000)
{
IList<Msg> messages = new List<Msg>();
var keepGoing = true;
while (keepGoing)
{
try
{
var msg = sub.NextMessage(timeout);
messages.Add(msg);
msg.Ack();
}
catch (NATSTimeoutException)
{
keepGoing = false;
}
}
return messages;
}
}
How to use
builder.Services.Configure<NatsProducerConfiguration>(options =>
builder.Configuration.GetSection("Nats").Bind(options));
var natsConfiguration = builder.Configuration.GetSection("Nats").Get<NatsProducerConfiguration>();
builder.Services.AddNatsClient(options =>
{
options.Servers = natsConfiguration?.Servers;
options.Url = natsConfiguration?.Url;
options.User = natsConfiguration?.User;
options.Password = natsConfiguration?.Password;
options.MaxReconnect = 5;
options.ReconnectWait = 5000;
});
Hopefully CreateStreamWhenDoesNotExist does what it says. By the way, JetStreamUtils was taken from the official C# NATS Client Samples.
I believe this fixes the pitfalls I described.
Perhaps you got a better idea?
public interface INatsPublisher
{
ValueTask PublishAsync<T>(string stream, string subject, T message) where T : class;
ValueTask PublishAsync<T>(string stream, string subject, T message, IEnumerable<(string, string)> headers)
where T : class;
ValueTask PublishDeduplicationIdAsync<T>(string stream, string subject, T message, string id)
where T : class;
}
public sealed class NatsPublisher : INatsPublisher
{
private readonly IConnection _connection;
private readonly Lazy<IJetStream> _jetStreamFactory;
public NatsPublisher(IConnection connection)
{
_connection = connection;
_jetStreamFactory = new Lazy<IJetStream>(() => connection.CreateJetStreamContext());
}
private IJetStream JetStream => _jetStreamFactory.Value;
public async ValueTask PublishAsync<T>(string stream, string subject, T message) where T : class
{
JetStreamUtils.CreateStreamOrUpdateSubjects(_connection, stream, subject);
var payload = JsonSerializer.SerializeToUtf8Bytes(message);
var msg = new Msg(subject, null, null, payload);
await JetStream.PublishAsync(msg);
}
public async ValueTask PublishAsync<T>(string stream, string subject, T message, IEnumerable<(string, string)> headers)
where T : class
{
JetStreamUtils.CreateStreamOrUpdateSubjects(_connection, stream, subject);
var payload = JsonSerializer.SerializeToUtf8Bytes(message);
var msg = new Msg(subject, null, null, payload);
foreach (var (header, val) in headers)
{
msg.Header[header] = val;
}
await JetStream.PublishAsync(msg);
}
public async ValueTask PublishDeduplicationIdAsync<T>(string stream, string subject, T message, string id)
where T : class
{
JetStreamUtils.CreateStreamOrUpdateSubjects(_connection, stream, subject);
var payload = JsonSerializer.SerializeToUtf8Bytes(message);
var msg = new Msg(subject, null, null, payload)
{
Header = { ["Nats-Msg-Id"] = id }
};
await JetStream.PublishAsync(msg);
}
}
I am new with c# and also with dapper. I wrote a simple console application that simulates the login process. I am trying to query a login table using dapper with parameters. I am not getting through even though the user and password are correct. I would appreciate any directions to accomplish a successful login testing.
public class Login
{
public string UserName { get; set; }
public string Password { get; set; }
public Login()
{
}
public Login(string username, string password)
{
UserName = username;
Password = password;
}
}
public static class Helper
{
public static string Con(string name)
{
return ConfigurationManager.ConnectionStrings[name].ConnectionString;
}
}
public class DataAccess
{
public List<Login> GetLogin(string username, string password)
{
using (IDbConnection connection = new SqlConnection(Helper.Con("Stock")))
{
var output = connection.Query<Login>("sp_GetLogin #UserName, #Password", new { UserName = username, Password = password }, commandType:CommandType.Text).ToList();
return output;
}
}
}
static void Main(string[] args)
{
string txtusername;
string txtpassword;
Console.WriteLine("Enter your Username:");
txtusername = Console.ReadLine();
Console.WriteLine("Enter your Password:");
txtpassword = Console.ReadLine();
Console.WriteLine("Username typed: {0}, Password typed: {1}", txtusername, txtpassword);
Login login = new Login();
DataAccess obj = new DataAccess();
obj.GetLogin(txtusername, txtpassword);
if (obj != null)
{
if (login.Password == txtpassword)
{
Console.WriteLine("User credentials successfull");
}
else Console.WriteLine("Password don't match");
}
else Console.WriteLine("Username don't match");
Console.ReadLine();
}
You're not using the return value of the DataAccess.GetLogin.
var login = obj.GetLogin(txtusername, txtpassword).FirstOrDefault();
Then do the credential check.
Login login = new Login();
DataAccess obj = new DataAccess();
obj.GetLogin(txtusername, txtpassword);
oh lawd.
DataAccess obj = new DataAccess();
Login login = obj.GetLogin(txtusername, txtpassword);
You really need to learn how to debug, stepping through each line of your code, examining what's going on and why it isn't what you expected. http://idownvotedbecau.se/nodebugging
I have a project with ftp and sftp calls (using System.Net.FtpClient and Renci.SshNet). I would like to have standard calls in both cases, i.e. call a Connect function and Upload function with the same parameters. I feel like I have to use an interface but I am green with interfaces and I am stuck. I need some directions here. I implemented 2 functions so far to test but it's not elegant and there must be some other way. For example I am passing an object as a parameter in GetWorkingDirectory but this feels wrong and I can't see how to do this correctly.
Here is the interface I have:
interface IRemoteCopy
{
object Connect(string Host, int Port, string Username, string Password, string Fingerprint);
string GetWorkingDirectory(object objRemote, string Directory);
}
Here are the classes I have:
public class FTPCopy : IRemoteCopy
{
public object Connect(string Host, int Port, string Username, string Password, string Fingerprint)
{
int ftpPort = 21; // default ftp port
if (Port == 0)
ftpPort = Port;
FtpClient ftp = new FtpClient();
ftp.Host = Host;
ftp.Port = ftpPort;
ftp.Credentials = new NetworkCredential(Username, Password);
return ftp;
}
public string GetWorkingDirectory(object objftp, string Directory)
{
FtpClient ftp = (FtpClient)objftp;
ftp.SetWorkingDirectory(Directory);
return ftp.GetWorkingDirectory();
}
}
public class SFTPCopy : IRemoteCopy
{
public object Connect(string Host, int Port, string Username, string Password, string Fingerprint)
{
int sftpPort = 22; // default sftp port
if (Port == 0)
sftpPort = Port;
ConnectionInfo connInfo = new ConnectionInfo(Host, sftpPort, Username, new AuthenticationMethod[]{
new PasswordAuthenticationMethod(Username, Password)
});
SftpClient sftp = new SftpClient(connInfo);
sftp.HostKeyReceived += delegate(object sender, HostKeyEventArgs e)
{
if (Fingerprint.ToLower() == (e.HostKeyName + " " + e.KeyLength + " " + BitConverter.ToString(e.FingerPrint).Replace("-", ":")).ToLower())
e.CanTrust = true;
else
e.CanTrust = false;
};
sftp.Connect();
return sftp;
}
public string GetWorkingDirectory(object objftp, string Directory)
{
return Directory;
}
}
Can anyone guide me here?
There are several ways you could solve this. I would suggest you write an interface IWorkingDirectory which the ftp clients implement, that has a method
GetWorkingDirectory(string dir).
The interface of IRemoteCopy's Connect method would become:
IWorkingDirectory Connect(string Host, int Port, string Username, string Password, string Fingerprint);
Then you could simplify the call to
public string GetWorkingDirectory(IWorkingDirectory client, string dir)
{
return client.GetWorkingDirectory(dir);
}
Depending on how this is called, you might even consider not implementing this method in IRemoteCopy at all, because most likely you will call Connect before that anyway, so you will be able to call the simple
var client = remoteCopy.Connect(...);
client.GetWorkingDirectory(dir);
You could then effectively make IRemoteCopy an abstract factory of IFtpClient (as the two client classes probably share more than the GetWorkingDirectory method I would suggest making an interface that offers all of the shared functionality).
I propose you check out this site about the open/closed principle:
http://joelabrahamsson.com/a-simple-example-of-the-openclosed-principle/
EDIT:
I just realized, the client classes were in different assemblies, so are not within your code. In this case it might be best to change the IRemoteCopy method signatures to not receive the clients as parameters. You could have a private field in the concrete classes that hold the respective clients, as obviously they will be always the same per class.
You can then set those fields on the Connect call, or directly at class instantiation. I would prefer the latter, because it seems less error prone for the users of IRemoteCopy.
Another possibilty would be to pack those clients into wrappers of your own (eiter by building an adapter - https://en.wikipedia.org/wiki/Adapter_pattern - or if the base clients are not sealed by inheriting from them), so you could use the interface base approach I proposed earlier.
After exploring generics, overloaded methods and interfaces, I came up with this solution. Let me know if you think there is something better:
IDirectory.cs:
using System;
using System.Text;
namespace ReleaseManager.Interfaces
{
interface IDirectory
{
void Connect(string Host, int Port, string Username, string Password, string Fingerprint);
string GetWorkingDirectory(string Directory);
void ListDirectory(string Directory);
void CreateDirectory(string Directory);
void DeleteDirectory(string Directory);
Boolean DirectoryExists(string Directory);
void WriteAllText(string FileName, string Content, Encoding enc);
void CopyFile(string srcFile, string dstFile);
void Disconnect();
}
}
Directory.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace ReleaseManager.BusinessObjects
{
public class RemoteDirInfo
{
public string Name { get; set; }
public string ModifiedDate { get; set; }
}
public class RemoteFileInfo
{
public string Name { get; set; }
public string ModifiedDate { get; set; }
public long Size { get; set; }
}
public class RemoteInfo
{
public string Error { get; set; }
public string CurrentDirectory { get; set; }
public List<RemoteDirInfo> DirInfo { get; set; }
public List<RemoteFileInfo> FileInfo { get; set; }
}
}
FTPDirectory.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ReleaseManager.Interfaces;
using System.Net.FtpClient;
using System.Net;
using System.Text;
using System.IO;
namespace ReleaseManager.BusinessObjects
{
public class FTPDirectory : IDirectory
{
private FtpClient client;
public RemoteInfo Info;
public FTPDirectory()
{
this.client = new FtpClient();
this.Info = new RemoteInfo();
this.Info.DirInfo = new List<RemoteDirInfo>();
this.Info.FileInfo = new List<RemoteFileInfo>();
this.Info.Error = "";
}
public void Connect(string Host, int Port, string Username, string Password, string Fingerprint)
{
int ftpPort = 21; // default ftp port
if (Port != 0)
ftpPort = Port;
this.client.Host = Host;
this.client.Port = ftpPort;
this.client.Credentials = new NetworkCredential(Username, Password);
}
public string GetWorkingDirectory(string Directory)
{
this.client.SetWorkingDirectory(Directory);
return this.client.GetWorkingDirectory();
}
public void ListDirectory(string Directory)
{
this.client.SetWorkingDirectory(Directory);
foreach (var item in this.client.GetListing(this.client.GetWorkingDirectory()))
{
switch (item.Type)
{
case FtpFileSystemObjectType.Directory:
if (item.Name != "." && item.Name != "..")
this.Info.DirInfo.Add(new RemoteDirInfo
{
Name = item.Name,
ModifiedDate = item.Modified.ToString("yyyy/MM/dd HH:mm:ss")
});
break;
case FtpFileSystemObjectType.File:
this.Info.FileInfo.Add(new RemoteFileInfo
{
Name = item.Name,
ModifiedDate = item.Modified.ToString("yyyy/MM/dd HH:mm:ss"),
Size = item.Size
});
break;
}
}
}
public void CreateDirectory(string Directory)
{
this.client.CreateDirectory(Directory);
}
public void DeleteDirectory(string Directory)
{
this.client.DeleteDirectory(Directory, true, FtpListOption.Recursive);
}
public void CopyFile(string srcFile, string dstFile)
{
using (var fileStream = System.IO.File.OpenRead(srcFile))
using (var ftpStream = this.client.OpenWrite(dstFile.Replace("\\", "/")))
{
var buffer = new byte[8 * 1024];
int count;
while ((count = fileStream.Read(buffer, 0, buffer.Length)) > 0)
{
ftpStream.Write(buffer, 0, count);
}
}
}
public void WriteAllText(string Filename, string Content, Encoding enc = null)
{
byte[] byteArray;
if (enc == null)
byteArray = Encoding.ASCII.GetBytes(Content);
else
byteArray = enc.GetBytes(Content);
using (MemoryStream stream = new MemoryStream(byteArray))
using (var ftpStream = this.client.OpenWrite(Filename.Replace("\\", "/")))
{
var buffer = new byte[8 * 1024];
int count;
while ((count = stream.Read(buffer, 0, buffer.Length)) > 0)
{
ftpStream.Write(buffer, 0, count);
}
}
}
public Boolean DirectoryExists(string Directory)
{
return this.client.DirectoryExists(Directory);
}
public void Disconnect()
{
this.client.Disconnect();
}
}
}
SFTPDirectory.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ReleaseManager.Interfaces;
using Renci.SshNet;
using Renci.SshNet.Common;
using Renci.SshNet.Sftp;
using System.Text;
using System.IO;
namespace ReleaseManager.BusinessObjects
{
public class SFTPDirectory : IDirectory
{
public SftpClient client;
public RemoteInfo Info;
public SFTPDirectory()
{
this.Info = new RemoteInfo();
this.Info.DirInfo = new List<RemoteDirInfo>();
this.Info.FileInfo = new List<RemoteFileInfo>();
this.Info.Error = "";
}
public void Connect(string Host, int Port, string Username, string Password, string Fingerprint)
{
int sftpPort = 22; // default sftp port
if (Port != 0)
sftpPort = Port;
ConnectionInfo connInfo = new ConnectionInfo(Host, sftpPort, Username, new AuthenticationMethod[]{
new PasswordAuthenticationMethod(Username, Password)
});
this.client = new SftpClient(connInfo);
this.client.HostKeyReceived += delegate(object sender, HostKeyEventArgs e)
{
if (Fingerprint.ToLower() == (e.HostKeyName + " " + e.KeyLength + " " + BitConverter.ToString(e.FingerPrint).Replace("-", ":")).ToLower())
e.CanTrust = true;
else
e.CanTrust = false;
};
this.client.Connect();
}
public string GetWorkingDirectory(string Directory)
{
return Directory;
}
public void ListDirectory(string Directory)
{
List<SftpFile> files = this.client.ListDirectory(Directory).ToList();
foreach (var file in files)
{
if (file.IsDirectory)
{
if (file.Name != "." && file.Name != "..")
this.Info.DirInfo.Add(new RemoteDirInfo
{
Name = file.Name,
ModifiedDate = file.LastWriteTime.ToString("yyyy/MM/dd HH:mm:ss")
});
}
else
{
this.Info.FileInfo.Add(new RemoteFileInfo
{
Name = file.Name,
ModifiedDate = file.LastWriteTime.ToString("yyyy/MM/dd HH:mm:ss"),
Size = file.Length
});
}
}
}
public void CreateDirectory(string Directory)
{
this.client.CreateDirectory(Directory);
}
public void DeleteDirectory(string Directory)
{
this.client.DeleteDirectory(Directory);
}
public void CopyFile(string srcFile, string dstFile)
{
using (var uplfileStream = System.IO.File.OpenRead(srcFile))
{
this.client.UploadFile(uplfileStream, dstFile.Replace("\\", "/"), true);
}
}
public void WriteAllText(string Filename, string Content, Encoding enc = null)
{
byte[] byteArray;
if (enc == null)
byteArray = Encoding.ASCII.GetBytes(Content);
else
byteArray = enc.GetBytes(Content);
using (MemoryStream stream = new MemoryStream(byteArray))
{
this.client.UploadFile(stream, Filename.Replace("\\", "/"), true);
}
}
public Boolean DirectoryExists(string Directory)
{
return this.client.Exists(Directory);
}
public void Disconnect()
{
this.client.Disconnect();
}
}
}
LocalDirectory.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ReleaseManager.Interfaces;
using System.Net;
using System.Text;
using System.IO;
namespace ReleaseManager.BusinessObjects
{
public class LocalDirectory : IDirectory
{
public RemoteInfo Info;
public LocalDirectory()
{
this.Info = new RemoteInfo();
this.Info.DirInfo = new List<RemoteDirInfo>();
this.Info.FileInfo = new List<RemoteFileInfo>();
this.Info.Error = "";
}
public void Connect(string Host, int Port, string Username, string Password, string Fingerprint)
{
}
public string GetWorkingDirectory(string Directory)
{
return Directory;
}
public void ListDirectory(string Directory)
{
DirectoryInfo di = new DirectoryInfo(Directory);
foreach (var item in di.EnumerateDirectories("*"))
{
if (item.Name != "." && item.Name != "..")
this.Info.DirInfo.Add(new RemoteDirInfo
{
Name = item.Name,
ModifiedDate = item.LastWriteTime.ToString("yyyy/MM/dd HH:mm:ss")
});
}
foreach (var item in di.EnumerateFiles("*"))
{
this.Info.FileInfo.Add(new RemoteFileInfo
{
Name = item.Name,
ModifiedDate = item.LastWriteTime.ToString("yyyy/MM/dd HH:mm:ss"),
Size = item.Length
});
}
}
public void CreateDirectory(string Directory)
{
System.IO.Directory.CreateDirectory(Directory);
}
public void DeleteDirectory(string Directory)
{
System.IO.Directory.Delete(Directory, true);
}
public void CopyFile(string srcFile, string dstFile)
{
System.IO.File.Copy(srcFile, dstFile);
}
public void WriteAllText(string Filename, string Content, Encoding enc = null)
{
if (enc == null)
System.IO.File.WriteAllText(Filename, Content);
else
System.IO.File.WriteAllText(Filename, Content, enc);
}
public Boolean DirectoryExists(string Directory)
{
return System.IO.Directory.Exists(Directory);
}
public void Disconnect()
{
}
}
}
Implementation of RemoteBrowse method:
public JsonResult RemoteBrowse(string Protocol, string Host, int Port, string Username, string Password, string Directory, string Fingerprint = "")
{
dynamic Connector = null;
MyMember.Init(User.Identity.Name);
if (MyMember.ID_Member > 0)
{
if (Protocol == "ftp")
Connector = new FTPDirectory();
else if (Protocol == "sftp")
Connector = new SFTPDirectory();
else if (Protocol == "local")
Connector = new LocalDirectory();
if (Connector != null)
{
try
{
Connector.Connect(Host, Port, Username, Password, Fingerprint);
while (true)
{
Boolean Mod = false;
if (Directory.Length >= 2)
{
if (Directory.Substring(0, 2) == "//")
{
Directory = Directory.Substring(1);
Mod = true;
}
else if (Directory.Substring(0, 2) == "..")
{
Directory = Directory.Substring(2);
Mod = true;
}
}
else if (Directory.Length >= 3)
{
if (Directory.Substring(0, 3) == "/..")
{
Directory = Directory.Substring(3);
Mod = true;
}
}
if (!Mod)
break;
}
if (Directory.Length > 1 && Directory != "/")
{
if (Directory.Substring(0, 1) != "/")
Directory = "/" + Directory;
if (Directory.Substring(Directory.Length - 1) == "/")
Directory = Directory.Substring(0, Directory.Length - 1);
if (Directory.Substring(Directory.Length - 3) == "/..") // go one directory up
{
Directory = Directory.Substring(0, Directory.Length - 3);
Directory = Directory.Substring(0, Directory.LastIndexOf('/'));
}
}
if (Directory == "")
Directory = "/";
Connector.Info.CurrentDirectory = Connector.GetWorkingDirectory(Directory);
Connector.ListDirectory(Directory);
Connector.Disconnect();
}
catch (Exception ex)
{
Connector.Info.Error = ex.Message;
if (ex.InnerException != null)
Connector.Info.Error += '\n' + ex.InnerException.Message;
}
}
}
return Json((Connector != null) ? Connector.Info : null, JsonRequestBehavior.AllowGet);
}
I implements IPasswordHasher
public class MyPasswordHasher : IPasswordHasher
{
public string HashPassword(string password)
{
using (SHA256 mySHA256 = SHA256Managed.Create())
{
byte[] hash = mySHA256.ComputeHash(Encoding.UTF8.GetBytes(password.ToString()));
StringBuilder hashSB = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
hashSB.Append(hash[i].ToString("x2"));
}
return hashSB.ToString();
}
}
public PasswordVerificationResult VerifyHashedPassword(
string hashedPassword, string providedPassword)
{
if (hashedPassword == HashPassword(providedPassword))
return PasswordVerificationResult.Success;
else
return PasswordVerificationResult.Failed;
}
}
I write in IdentityConfig
manager.PasswordHasher = new MyPasswordHasher();
but var user = await UserManager.FindAsync(model.Email, model.Password); in AccountController/Login do not use MyPasswordHaser.
How can I use it in Identity 2.1?
You have to plug it into the UserManager:
public class AppUserManager : UserManager<AppUser, int>
{
public AppUserManager(AppUserStore a_store)
: base(a_store)
{
_container = a_container;
_emailService = _container.GetInstance<IEmailService>();
PasswordHasher = new AppPasswordHasher();
}
}
Use:
PasswordHasher = new MyPasswordHasher();
in UserManager ctor!
im am trying to make for a school project a client-server application in C#
My problem is that one class gets serialized ok and is sent over the socket, and the other is not and i cant figure it out.
Employee class (and also Bonus) is getting serialized, but when i try to pass to
the formater a Transfer instance
formatter.Serialize(stream, transferObj);
it throws exception: NotSupportedException
with message: Memory stream is not expandable.
sendToServer()
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
System.Net.IPAddress ipAdd = System.Net.IPAddress.Parse("127.0.0.1");
System.Net.IPEndPoint remoteEP = new IPEndPoint(ipAdd, 6666);
socket.Connect("127.0.0.1", 6666);
Transfer t = new Transfer();
Employee e = new Employee();
Bonus b = new Bonus(); b.setAmmount(234); b.setDescription("xxxx");
e.getBonuses().Add(b);
byte[] buffer = new byte[1000];
System.Console.WriteLine("client started");
IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream(buffer);
formatter.Serialize(stream, e);
// Employee and Bonus are serialized but not Transfer
stream.Flush();
socket.Send(buffer,buffer.Length,0);
Employee Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Permissions;
using System.Runtime.Serialization;
namespace Entity
{
[Serializable]
public class Employee : ISerializable
{
private int id;
private long version;
private String username;
private String password;
private String role;
private String name;
private String surname;
private long salary;
private DateTime experience;
private DateTime birthDate;
private String sex;
private List<Bonus> bonuses;
public Employee() {
bonuses = new List<Bonus>();
}
protected Employee(SerializationInfo info, StreamingContext context)
{
id = info.GetInt32("id");
version = info.GetInt32("version");
username = info.GetString("username");
password = info.GetString("password");
role = info.GetString("role");
name = info.GetString("name");
surname = info.GetString("surname");
salary = info.GetInt32("salary");
experience = (DateTime) info.GetValue("exp", typeof(DateTime));
birthDate = (DateTime)info.GetValue("birth", typeof(DateTime));
sex = info.GetString("sex");
bonuses = (List<Bonus>) info.GetValue("bonuses", typeof(List<Bonus>));
}
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getSurname()
{
return surname;
}
public void setSurname(String surname)
{
this.surname = surname;
}
public long getSalary()
{
return salary;
}
public void setSalary(long salary)
{
this.salary = salary;
}
public DateTime getExperience()
{
return experience;
}
public void setExperience(DateTime experience)
{
this.experience = experience;
}
public DateTime getBirthDate()
{
return birthDate;
}
public void setBirthDate(DateTime birthDate)
{
this.birthDate = birthDate;
}
public List<Bonus> getBonuses()
{
return bonuses;
}
public void setBonuses(List<Bonus> bonuses)
{
this.bonuses = bonuses;
}
public override string ToString()
{
return name + " " + surname;
}
public override int GetHashCode()
{
int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
public override bool Equals(System.Object obj)
{
// If parameter is null return false.
if (obj == null)
{
return false;
}
// If parameter cannot be cast to Point return false.
Employee p = obj as Employee;
if ((System.Object)p == null)
{
return false;
}
// Return true if the fields match:
return id == p.id;
}
public void setSex(String sex)
{
this.sex = sex;
}
public String getSex()
{
return sex;
}
public long getVersion()
{
return version;
}
public void setVersion(long version)
{
this.version = version;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public String getRole()
{
return role;
}
public void setRole(String role)
{
this.role = role;
}
#region ISerializable Members
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("id", id);
info.AddValue("version", version);
info.AddValue("username", username);
info.AddValue("password", password);
info.AddValue("role", role);
info.AddValue("name", name);
info.AddValue("surname", surname);
info.AddValue("salary", salary);
info.AddValue("exp", experience);
info.AddValue("birth", birthDate);
info.AddValue("sex", sex);
info.AddValue("bonuses", bonuses);
}
#endregion
}
}
Transfer Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Permissions;
using System.Runtime.Serialization;
namespace Entity
{
[Serializable]
public class Transfer : ISerializable
{
private Employee employee;
private String method;
private String message;
private List<Employee> queriedEmployees;
public Transfer() {
queriedEmployees = new List<Employee>();
}
protected Transfer(SerializationInfo info, StreamingContext context)
{
employee = (Employee) info.GetValue("employee", typeof(Employee) );
method = info.GetString("method");
message = info.GetString("message");
queriedEmployees = (List<Employee>) info.GetValue("qe", typeof(List<Employee>));
}
public Employee getEmployee()
{
return employee;
}
public String getMethod()
{
return method;
}
public String getMessage()
{
return message;
}
public List<Employee> getQueriedEmployees()
{
return queriedEmployees;
}
public void setEmployee(Employee e)
{
employee = e;
}
public void setMessage(String mes)
{
message = mes;
}
public void setMethod(String meth)
{
method = meth;
}
public void setQueriedEmployees(List<Employee> elist)
{
queriedEmployees = elist;
}
#region ISerializable Members
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("employee", employee);
info.AddValue("method", method);
info.AddValue("message", message);
info.AddValue("qe", queriedEmployees);
}
#endregion
}
}
It doesn't let you because you explicitly initialize the MemoryStream with a fixed length byte array. See this: http://weblogs.asp.net/ashicmahtab/archive/2008/08/25/memorystream-not-expandable-invalid-operation-exception.aspx
Try something like this instead:
IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream();
formatter.Serialize(stream, e);
byte[] buffer = ((MemoryStream)stream).ToArray();
By providing a buffer to the MemoryStream constructor you are fixing it to that size. If you just use the default constructor, the stream should be expandable to whatever size is required.
Stream stream = new MemoryStream();
See this blog entry
setting a larger buffer will let me serialize Transfer class