- Details
- Written by: Stanko Milosev
- Category: C#
- Hits: 821
private DataTable CreateMasterDataTable()
{
DataTable dtMaster = new DataTable("Master");
dtMaster.Columns.Add("Id", typeof(int));
dtMaster.Columns.Add("SomeText", typeof(string));
dtMaster.PrimaryKey =
[
dtMaster.Columns["Id"]
];
return dtMaster;
}
Now detail DataTable:
private DataTable CreateDetailDataTable()
{
DataTable dtDetail = new DataTable("Detail");
dtDetail.Columns.Add("Id", typeof(int));
dtDetail.Columns.Add("MasterId", typeof(int));
dtDetail.Columns.Add("SomeText", typeof(string));
dtDetail.PrimaryKey =
[
dtDetail.Columns["Id"]
, dtDetail.Columns["MasterId"]
];
return dtDetail;
}
DataSet:
DataSet dsMasterDetail = new DataSet("MasterDetail");
dsMasterDetail.Tables.Add(CreateMasterDataTable());
dsMasterDetail.Tables.Add(CreateDetailDataTable());
Relation and add relation to DataSet:
DataRelation relMasterDetail = new DataRelation("MasterDetailRelation"
, dsMasterDetail.Tables["Master"].Columns["Id"]
, dsMasterDetail.Tables["Detail"].Columns["MasterId"]
);
dsMasterDetail.Relations.Add(relMasterDetail);
Now, lets create BindingSource and attach it to DataSource of DataGridView:
var dsMasterDetail = CreateMasterDetailDataSet();
BindingSource bsMaster = new BindingSource
{
DataSource = dsMasterDetail,
DataMember = "Master"
};
dgvMaster.DataSource = bsMaster;
BindingSource bsDetail = new BindingSource
{
DataSource = bsMaster,
DataMember = "MasterDetailRelation"
};
dgvDetail.DataSource = bsDetail;
Here notice that DataSource of detail BindingSource I have attached master BindingSource, as DataMember name of relation:
BindingSource bsDetail = new BindingSource
{
DataSource = bsMaster,
DataMember = "MasterDetailRelation"
};
Example download from here.
- Details
- Written by: Stanko Milosev
- Category: C#
- Hits: 1121
public class SimpleCommandViewModel: INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
private RelayCommand _sampleCommand;
public SimpleCommandViewModel()
{
_sampleCommand = new RelayCommand(ExecuteSampleCommand);
}
public void ExecuteSampleCommand()
=> MessageBox.Show("Hello world");
public RelayCommand SampleCommand
{
get => _sampleCommand;
set
{
if (_sampleCommand == value)
{
return;
}
_sampleCommand = value;
OnPropertyChanged();
}
}
}
Here notice:
new RelayCommand(ExecuteSampleCommand);That means that by default my button is enabled, in comparsion of Klaus Loeffelmann article:
new RelayCommand(ExecuteSampleCommand, CanExecuteSampleCommand);Where his button will enabled only if CanExecuteSampleCommand is set to true. Now, build it at least once. Then in Properties -> DataBindings -> Command -> add new Object DataSource -> choose SimpleCommandViewModel, after choose SampleCommand from dropdown list. In Form Load event add code:
private void Form1_Load(object sender, EventArgs e)
{
simpleCommandViewModelBindingSource.DataSource = new SimpleCommandViewModel();
}
Example download from here.
- Details
- Written by: Stanko Milosev
- Category: C#
- Hits: 5320
Natively WebAPI doesn't support binding of multiple POST parameters.Here I already gave two examples of WebAPI with multiple Post parameters. Now I will use similiar approach to send image plus additional data, like file and folder name. First don't forget in Program.cs to add Service:
builder.Services.AddMvc().AddNewtonsoftJson();Controller:
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
namespace UploadImageServer.Controllers;
public class UploadImageController : Controller
{
[HttpPost]
[Route("UploadImage")]
public async Task<IActionResult> UploadImage([FromBody] JObject? data)
{
if (data is null) return BadRequest(new { message = "No image." });
string? base64Image = data["image"]?.ToString();
if (base64Image == null) return BadRequest(new { message = "No image." });
byte[] imageBytes = Convert.FromBase64String(base64Image);
Directory.CreateDirectory(data["folderName"]?.ToString() ?? string.Empty);
string imagePath = $"{data["folderName"]}\\{data["fileName"]}";
await System.IO.File.WriteAllBytesAsync(imagePath, imageBytes);
return Ok(new { message = "Image uploaded successfully." });
}
}
Server download from here.
---
Client:
using Newtonsoft.Json.Linq;
using System.Net.Http.Headers;
string imageUrl = "spring.jpg";
string base64Image = ConvertImageToBase64(imageUrl);
var jsonData = new JObject
{
["image"] = base64Image
, ["fileName"] = "magnolia.jpg"
, ["folderName"] = "spring"
};
string jsonContent = jsonData.ToString();
using HttpClient client = new HttpClient();
StringContent content = new StringContent(jsonContent);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage response = await client.PostAsync("https://localhost:7028/UploadImage", content);
if (response.IsSuccessStatusCode)
{
Console.WriteLine("Image uploaded successfully!");
}
else
{
Console.WriteLine("Failed to upload image. Status code: " + response.StatusCode);
}
static string ConvertImageToBase64(string imagePath)
{
byte[] imageBytes = File.ReadAllBytes(imagePath);
return Convert.ToBase64String(imageBytes);
}
Client download from here.
- Details
- Written by: Stanko Milosev
- Category: C#
- Hits: 2439
Log4NetLogger log4NetLogger = new Log4NetLogger(log);
AsyncFtpClient client = new AsyncFtpClient(host, user, pass);
client.ValidateCertificate += OnValidateCertificate;
client.Logger = new FtpLogAdapter(log4NetLogger);
await client.AutoConnect();
await client.UploadFile(fileName, "/public_html/kmlTestDelete/test.kml");
private void OnValidateCertificate(BaseFtpClient control, FtpSslValidationEventArgs e)
{
e.Accept = true;
}
The method OnValidateCertificate I am using to accept any certificate, this part of code I took from here
Class Log4NetLogger looks like this:
using log4net;
using Microsoft.Extensions.Logging;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace FluentFTPasyncExample;
public class Log4NetLogger : ILogger
{
private readonly ILog _log;
public Log4NetLogger(ILog log)
{
_log = log;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
string message = $"{formatter(state, exception)} {exception}";
if (!string.IsNullOrEmpty(message))
{
switch (logLevel)
{
case LogLevel.Critical:
_log.Fatal(message);
break;
case LogLevel.Debug:
case LogLevel.Trace:
_log.Debug(message);
break;
case LogLevel.Error:
_log.Error(message);
break;
case LogLevel.Information:
_log.Info(message);
break;
case LogLevel.Warning:
_log.Warn(message);
break;
default:
_log.Warn($"Encountered unknown log level {logLevel}, writing out as Info.");
_log.Info(message, exception);
break;
}
}
}
public bool IsEnabled(LogLevel logLevel)
{
switch (logLevel)
{
case LogLevel.Critical:
return _log.IsFatalEnabled;
case LogLevel.Debug:
case LogLevel.Trace:
return _log.IsDebugEnabled;
case LogLevel.Error:
return _log.IsErrorEnabled;
case LogLevel.Information:
return _log.IsInfoEnabled;
case LogLevel.Warning:
return _log.IsWarnEnabled;
default:
throw new ArgumentOutOfRangeException(nameof(logLevel));
}
}
public IDisposable BeginScope<TState>(TState state)
{
return null!;
}
}
Notice that I am injecting log4net in constructor.
Example download from here.