- Details
- Written by: Stanko Milosev
- Category: C#
- Hits: 5548
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: 3224
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.
- Details
- Written by: Stanko Milosev
- Category: C#
- Hits: 1690
First console example
Start new console app Install package log4net Add XML file, name it like "log4netConfiguration.xml" and in properties set "Copy to Output Directory" to "Copy always":
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="myConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-4timestamp [%thread] %-5level %logger %ndc - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="myConsoleAppender" />
</root>
</log4net>
Here notice the name of appender: myConsoleAppender
Code:
using log4net;
using log4net.Repository;
using System.Reflection;
if (!File.Exists("log4netConfiguration.xml"))
throw new Exception("File log4netConfiguration.xml does not exist");
ILoggerRepository loggerRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
log4net.Config.XmlConfigurator.Configure(loggerRepository, new FileInfo("log4netConfiguration.xml"));
var log = LogManager.GetLogger(MethodBase.GetCurrentMethod()?.DeclaringType);
log.Debug("test");
Example download from here
Second console and file example
Just change XML to:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="myConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-4timestamp [%thread] %-5level %logger %ndc - %message%newline" />
</layout>
</appender>
<appender name="myRollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="example.log" />
<appendToFile value="true" />
<maximumFileSize value="100KB" />
<maxSizeRollBackups value="2" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level %thread %logger - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="myConsoleAppender" />
<appender-ref ref="myRollingFileAppender" />
</root>
</log4net>
Notice myRollingFileAppender.
Third WinForms and TextBox example
This example I took from here XML configuration:<?xml version="1.0" encoding="utf-8" ?> <log4net> <appender name="myTextBoxAppender" type="log4netWinFormsExample.TextBoxAppender, log4netWinFormsExample"> <formName value="Form1"/> <textBoxName value="textBox1"/> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date %-5level %logger - %message" /> </layout> </appender> <root> <level value="DEBUG" /> <appender-ref ref="myTextBoxAppender" /> </root> </log4net>Here notice that I have added namespace "log4netWinFormsExample" in the type attribute of appender node:
<appender name="myTextBoxAppender" type="log4netWinFormsExample.TextBoxAppender, log4netWinFormsExample">TextBoxAppender class:
using log4net.Appender;
namespace log4netWinFormsExample;
public class TextBoxAppender : AppenderSkeleton
{
private TextBox _textBox;
public TextBox AppenderTextBox
{
get
{
return _textBox;
}
set
{
_textBox = value;
}
}
public string FormName { get; set; }
public string TextBoxName { get; set; }
private Control FindControlRecursive(Control root, string textBoxName)
{
if (root.Name == textBoxName) return root;
foreach (Control c in root.Controls)
{
Control t = FindControlRecursive(c, textBoxName);
if (t != null) return t;
}
return null;
}
protected override void Append(log4net.Core.LoggingEvent loggingEvent)
{
if (_textBox == null)
{
if (String.IsNullOrEmpty(FormName) ||
String.IsNullOrEmpty(TextBoxName))
return;
Form form = Application.OpenForms[FormName];
if (form == null)
return;
_textBox = (TextBox)FindControlRecursive(form, TextBoxName);
if (_textBox == null)
return;
form.FormClosing += (s, e) => _textBox = null;
}
_textBox.Invoke((MethodInvoker)delegate
{
_textBox.AppendText(loggingEvent.RenderedMessage + Environment.NewLine);
});
}
}
Here notice line:
_textBox.AppendText(loggingEvent.RenderedMessage + Environment.NewLine);Instead you could write:
_textBox.AppendText(RenderLoggingEvent(loggingEvent));To take advantage of a pattern layout as described in this comment. The main code:
using System.Reflection;
using log4net;
using log4net.Repository;
namespace log4netWinFormsExample;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnLogIt_Click(object sender, EventArgs e)
{
if (!File.Exists("log4netConfiguration.xml"))
throw new Exception("File log4netConfiguration.xml does not exist");
ILoggerRepository loggerRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
log4net.Config.XmlConfigurator.Configure(loggerRepository, new FileInfo("log4netConfiguration.xml"));
var log = LogManager.GetLogger(MethodBase.GetCurrentMethod()?.DeclaringType);
log.Debug("test");
}
}
Example download from here
- Details
- Written by: Stanko Milosev
- Category: C#
- Hits: 2501
First example
WebAPI:
[HttpPost]
public string Post(string value1, string value2)
{
return $"Sent: {value1}, {value2}";
}
Console:
Console.WriteLine("************* POST *************");
HttpClient httpClientPost = new HttpClient();
Task<HttpResponseMessage> httpResponseMessage = httpClientPost.PostAsync(@"https://localhost:7037/api/Values?value1=test1&value2=test2'", null);
Task<string> httpClientPostResult = httpResponseMessage.Result.Content.ReadAsStringAsync();
Console.WriteLine(httpClientPostResult.Result);
Example download from here
---
Second example.
First install Microsoft.AspNetCore.Mvc.NewtonsoftJson In \WebApi\WebApi\Program.cs add line:builder.Services.AddMvc().AddNewtonsoftJson();Now Program.cs looks like:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddMvc().AddNewtonsoftJson();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Controller:
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
namespace WebApi.Controllers;
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// POST api/<ValuesController>
[HttpPost]
public string Post([FromBody] JObject data)
{
return "test";
}
}
Console:
using System.Text;
Console.WriteLine("************* POST *************");
HttpClient httpClientPost = new HttpClient();
Task<HttpResponseMessage> httpResponseMessage = httpClientPost.PostAsync(@"https://localhost:7037/api/Values"
, new StringContent(@"{""additionalProp1"":[""string""],""additionalProp2"":[""string""],""additionalProp3"":[""string""]}"
, Encoding.UTF8
, "application/json"));
Task<string> httpClientPostResult = httpResponseMessage.Result.Content.ReadAsStringAsync();
Console.WriteLine(httpClientPostResult.Result);
Taken from here.
Example download from here.