12 Ekim 2020

Asp Net Core ile ModelState Validation için Custom Yanıt Dönen Middleware

ASP.Net Core Web Api de DataAnnotations attribute ile uymayan durumlarda dönen yanıt örnek User.cs için aşağıdaki gibidir. 

 { "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", 

 "title": "One or more validation errors occurred.",

 "status": 400, 

 "traceId": "|c591e8b8-46918ec46443b7d8.", 

"errors": { 

"Username": [ "The Username field is required.", "En az sekiz karakterli bir kullanıcı adı giriniz." ] 

    } 

 }

 Bizim tüm uygulama boyunca generic api responseda formatı aşağıda ki gibi istediğimizi varsayalım 

{ "Status": 400,

 "IsSuccess": false,

 "Result": null,

 "Errors":

 "The Username field is required. \r\n En az sekiz karakterli bir kullanıcı adı giriniz."

  }

 Bunun için yapılan adımlar aşağıdaki gibidir.

#
// ApiResponse.cs //

using System;
using Microsoft.Extensions.Logging;

namespace CustomMiddlewareForModelState.Models
{
public class ApiResponse<TResult>
{
public int Status { get; set; }
public bool IsSuccess { get; set; }
public TResult Result { get; set; }
public string Errors { get; set; }

public ApiResponse<TResult> Invoke(Func<TResult> func, ILogger _logger)
{
try
{
Result = func.Invoke();
Status = 200;
IsSuccess = true;
Errors = string.Empty;
}
catch (Exception ex)
{
Guid? exceptionId = Guid.NewGuid();
Result = default(TResult);
IsSuccess = false;
Errors = $"Genel bir hata meydana geldi. Lütfen {exceptionId} takip numarası ile geri dönüşte bulunun. ";

_logger?.LogError("ExceptionId : " + exceptionId.ToString()
+ " , Exception: " + ex.ToString());
}
return this;
}
}
}

// ModelStateFeature.cs //

using Microsoft.AspNetCore.Mvc.ModelBinding;

namespace CustomMiddlewareForModelState.Models
{
public class ModelStateFeature
{
public ModelStateDictionary ModelState { get; set; }

public ModelStateFeature(ModelStateDictionary state)
{
ModelState = state;
}
}

}

// ModelStateFeatureFilter.cs //


using Microsoft.AspNetCore.Mvc.Filters;
using System.Threading.Tasks;
using CustomMiddlewareForModelState.Models;

namespace CustomMiddlewareForModelState.Filters
{
public class ModelStateFeatureFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var state = context.ModelState;
context.HttpContext.Features.Set(new ModelStateFeature(state));
await next();
}
}
}

// ModelStateResponseMiddleware.cs //

using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using CustomMiddlewareForModelState.Models;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;

namespace CustomMiddlewareForModelState.Middlewares{
public class ModelStateResponseMiddleware{
private readonly RequestDelegate next;
public ModelStateResponseMiddleware(RequestDelegate next)
{
this.next = next;
}

public async Task Invoke(HttpContext context)
{
Stream originalBody = context.Response.Body;
try
{
using (var ms = new MemoryStream())
{
context.Response.Body = ms;
await next(context);
ms.Position = 0;
string responseBody = new StreamReader(ms).ReadToEnd();

if (context.Response.StatusCode == 400)
{
var modelState = context.Features.Get<ModelStateFeature>()?.ModelState;
if (modelState != null
&& !modelState.IsValid
&& modelState.Count > 0)
{
var errors = modelState.Values.Where(v => v.Errors.Count > 0)
.SelectMany(v => v.Errors)
.Select(v => v.ErrorMessage)
.ToList();

var apiResponse = new ApiResponse<object>(){
IsSuccess = false,
Result = null,
Status = 400,
Errors = string.Join(" \r\n ", errors)
};

context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
context.Response.ContentType = "application/json";
string strApiResponse = JsonConvert.SerializeObject(apiResponse);
var data = System.Text.Encoding.UTF8.GetBytes(strApiResponse);
ms.Position = 0;
await ms.WriteAsync(data);
ms.SetLength(data.Length);
}
}
ms.Position = 0;
await ms.CopyToAsync(originalBody);
}
}
finally
{
context.Response.Body = originalBody;
}
}
}
}

// Startup.cs //
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using CustomMiddlewareForModelState.Filters;
using CustomMiddlewareForModelState.Middlewares;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace CustomMiddlewareForModelState
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(opts => {
opts.Filters.Add(typeof(ModelStateFeatureFilter),int.MinValue);
});
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseHttpsRedirection();

app.UseRouting();

app.UseAuthorization();

app.UseMiddleware<ModelStateResponseMiddleware>();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}

// User.cs //

using System.ComponentModel.DataAnnotations;

namespace CustomMiddlewareForModelState.Models
{
public class User
{
[Required]
[StringLength(int.MaxValue, MinimumLength = 1, ErrorMessage = "En az sekiz karakterli bir kullanıcı adı giriniz.")]
public string Username { get; set; }

[Required]
[StringLength(int.MaxValue, MinimumLength = 1, ErrorMessage = "En az sekiz karakterli bir şifre giriniz.")]
public string Password { get; set; }
}
}

// TestController.cs //


using System;
using Microsoft.AspNetCore.Mvc;
using CustomMiddlewareForModelState.Models;

namespace CustomMiddlewareForModelState.Controllers{
[Route("api/[controller]")]
[ApiController]
public class TestController : Controller
{
[HttpPost]
public IActionResult Post(User user)
{
var resp = new ApiResponse<Guid>().Invoke(() =>
{
if (ModelState.IsValid)
{
return Guid.NewGuid();
}
throw new Exception("Validasyon hatası!");
}, null);

if (resp.Status == 200)
return Ok(resp);
else return BadRequest(resp);
}
}
}

ModelState Başarısızsa dönen yanıt

{
"Status": 400,
"IsSuccess": false,
"Result": null,
"Errors": "The Username field is required. \r\n En az sekiz karakterli bir kullanıcı adı giriniz."
}

Başarılıysa Dönen Yanıt

{
"status": 200,
"isSuccess": true,
"result": "fdc56d1b-1ee8-43ce-b7d8-46ba36bee668",
"errors": ""
}
 #

28 Eylül 2020

Asp.Net Core ile Kendi Captcha Kodunu Oluştur


Installed Packages 
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.1" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta0010" />

TreeView
/Common
- Captcha.cs
- CaptchaManager.cs
/Controllers
- HomeController.cs
/Controllers/Api
- CaptchaController.cs
/ViewModels/Home
- IndexViewModel.cs
/Views/Home
- Index.cshtml

// Captcha.cs
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using System;
using System.IO;
using System.Text;

namespace ApsNetCoreCaptchaSample.Common
{
public class Captcha : IDisposable
{
private static char[] _charset = null;
private static char[] charset
{
get
{
if (_charset == null)
{
var sb = new StringBuilder();
for (int i = 2; i < 10; i++)
{
sb.Append(i.ToString());
}
for (int c = 'a'; c < 'z'; c++)
{
if (c == 'i' || c == 'x' || c == 'w'
|| c == 'o' || c == 'l' || c == 'u'
|| c == 'j' || c == 'z' || c == 'm'
|| c == 'c')
continue;
sb.Append((char)c);
}
for (int c = 'A'; c < 'Z'; c++)
{
if (c == 'I' || c == 'X' || c == 'W'
|| c == 'O' || c == 'U' || c == 'M'
|| c == 'J' || c == 'Z' || c == 'C')
continue;
sb.Append((char)c);
}
_charset = sb.ToString().ToCharArray();
}
return _charset;
}
}
public DateTimeOffset CreateDate { get; }
public Guid Id { get; }
private string Text { get; }
public byte[] Image { get; private set; }

public string ToBase64()
{
if (Image == null)
return string.Empty;
return Convert.ToBase64String(Image);
}

public bool Confirm(string text)
{
if (string.IsNullOrWhiteSpace(text))
return false;
return text == Text;
}


public Captcha()
{
Text = GenerateRandomText();
Image = DrawCaptcha(Text);
Id = Guid.NewGuid();
CreateDate = DateTimeOffset.UtcNow;
}
private readonly static string[] fonts = new string[3] {
"Arial", "Verdana", "Times New Roman" };
private byte[] DrawCaptcha(string text)
{
byte[] result = null;
float position = 0;
using (var img = new Image<Rgba32>(90, 40))
{
var x = 20;
var y = 8;
var backColor = Color.White;
img.Mutate(ctx => ctx.BackgroundColor(Color.White));
float maxX = 0;
for (int i = 0; i < text.Length; i++)
{
var c = text[i];
var random = new Random();

var font = SystemFonts.CreateFont(
fonts[random.Next(0, fonts.Length - 1)],
random.Next(24, 28),
random.Next(0, 1) == 0 ? FontStyle.Regular : FontStyle.Italic);
var location = new PointF(x + position, y + random.Next(0, 4));
img.Mutate(ctx => ctx.DrawText(c.ToString(), font, Color.Black, location));
position += TextMeasurer.Measure(c.ToString(), new RendererOptions(font, location)).Width - 4;
maxX = position;
var builder = new AffineTransformBuilder();
img.Mutate(ctx => ctx.Transform(
builder.PrependRotationDegrees((float)(random.NextDouble()), new PointF((float)2, (float)4))));
}
for (int i = 0; i < 2; i++)
{
var r = new Random();
img.Mutate(ctx => ctx.DrawLines(Color.Black, 2
, new PointF[] { new PointF(r.Next(20, 26), r.Next(8, 36)),
new PointF(r.Next(Convert.ToInt32(maxX+1),Convert.ToInt32(89)), r.Next(8, 36)) }));
}
using (var ms = new MemoryStream())
{
img.SaveAsPng(ms);
result = ms.ToArray();
}
}
return result;
}
private string GenerateRandomText()
{
var sb = new StringBuilder();
for (int i = 0; i < 5; i++)
{
var random = new Random();
var index = random.Next(0, charset.Length - 1);
sb.Append(charset[index]);
}
return sb.ToString();
}

public void Dispose()
{
Image = null;
}
}
}

// CaptchaManager

using System;
using System.Collections.Generic;
using System.Linq;

namespace ApsNetCoreCaptchaSample.Common
{
public static class CaptchaManager
{
private static readonly List<Captcha> captchas = new List<Captcha>();
public static (Guid Id, string Image) New()
{
using (var captcha = new Captcha())
{
captchas.Add(captcha);
return (captcha.Id, captcha.ToBase64());
}
}

public static bool Confirm(Guid id, string text)
{
captchas.RemoveAll(q => q.CreateDate < DateTimeOffset.UtcNow.AddMinutes(-2));
var captcha = captchas.SingleOrDefault(q => q.Id == id);
if (captcha != null && captcha.Confirm(text))
{
captchas.Remove(captcha);
return true;
}
return false;
}
}
}

// CaptchaController.cs

using ApsNetCoreCaptchaSample.Common;
using Microsoft.AspNetCore.Mvc;

namespace ApsNetCoreCaptchaSample.Controllers.Api
{
[Route("api/[controller]")]
[ApiController]
public class CaptchaController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
var captcha = CaptchaManager.New();
var response = new
{
id = captcha.Id,
image = captcha.Image
};
return Ok(response);
}
}
}

// HomeController.cs

using ApsNetCoreCaptchaSample.Common;
using ApsNetCoreCaptchaSample.ViewModels.Home;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

namespace ApsNetCoreCaptchaSample.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;

public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}

public IActionResult Index()
{
return View();
}

[HttpPost]
public string Index(IndexViewModel model)
{
return CaptchaManager.Confirm(model.CaptchaId, model.Captcha).ToString();
}
}
}


// IndexViewModel.cs

using System;

namespace ApsNetCoreCaptchaSample.ViewModels.Home
{
public class IndexViewModel
{
public string Captcha { get; set; }
public Guid CaptchaId { get; set; }
}
}

// Index.cshtml

@model ApsNetCoreCaptchaSample.ViewModels.Home.IndexViewModel
@{
Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Captcha Sample</title>
</head>
<body>
<form method="post">
<img id="captchaImage"/>
@Html.TextBoxFor(q => q.Captcha, new { placeholder = "Captcha" })
<br>
<input type="submit" id="send" name="send" value="Send">
@Html.HiddenFor(q => q.CaptchaId)
</form>

<script>
var captchaImage = document.getElementById('captchaImage');
var captchaId = document.getElementById('CaptchaId');

function newCaptcha() {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/api/captcha', true)
xhr.onreadystatechange = function () {
if (this.readyState != 4) return;
if (this.status == 200) {
var resp = JSON.parse(this.responseText);
captchaId.value = resp.id;
captchaImage.src = 'data:image/png;base64, ' + resp.image;
}
}
xhr.send();
}
captchaImage.addEventListener('click', function () {
newCaptcha();
});

newCaptcha();

</script>
</body>
</html>

30 Nisan 2020

HTML Tablo da Genişletilebilir Satır

//
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
        integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">

    <style>
        .btnExp {
            border: 0px;
            background: transparent;
            font-weight: bold;
        }

        .hide {
            display: none;
        }

        .expBody {
            background-color: #f8f9fa;
            ;
        }
    </style>
</head>

<body>
    <table class="table expandableTable">
        <thead>
            <tr>
                <th scope="col">#</th>
                <th scope="col">First</th>
                <th scope="col">Last</th>
                <th scope="col">Handle</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <th scope="row">
                    <button type="button" class="btnExp">+</button>
                </th>
                <td>Mark</td>
                <td>Otto</td>
                <td>@mdo</td>
            </tr>
            <tr class="expBody hide">
                <td colspan="4">XXX</td>
            </tr>
            <tr>
                <th scope="row">
                    <button class="btnExp">+</button>
                </th>
                <td>Jacob</td>
                <td>Thornton</td>
                <td>@fat</td>
            </tr>
            <tr class="expBody hide">
                <td colspan="4">ZZZ</td>
            </tr>
            <tr>
                <th scope="row">
                    <button class="btnExp">+</button>
                </th>
                <td>Larry</td>
                <td>the Bird</td>
                <td>@twitter</td>
            </tr>
            <tr class="expBody hide">
                <td colspan="4">YYY</td>
            </tr>
        </tbody>
    </table>
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
        integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"
        crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
        integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
        crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
        integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
        crossorigin="anonymous"></script>

    <script>
        function hasClass(ele, cls) {
            return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
        }

        function addClass(ele, cls) {
            if (!hasClass(ele, cls)) ele.className += " " + cls;
        }

        function removeClass(ele, cls) {
            if (hasClass(ele, cls)) {
                var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
                ele.className = ele.className.replace(reg, ' ');
            }
        }

        function expandableTable() {
            var expandableTables = document.getElementsByClassName('expandableTable');
            if (expandableTables != null) {
                for (var t = 0; t < expandableTables.length; t++) {
                    tt = expandableTables[t];
                    var expBtns = tt.getElementsByClassName('btnExp');
                    if (expBtns != null) {
                        for (var b = 0; b < expBtns.length; b++) {
                            var expBtn = expBtns[b];
                            expBtn.addEventListener('click', function (e) {
                                var btn = e.srcElement;
                                var _tr = btn.parentElement.parentElement.nextElementSibling;
                                if (btn.innerText == '-') {
                                    btn.innerText = '+';
                                    addClass(_tr,'hide');
                                } else {
                                    btn.innerText = '-';
                                    removeClass(_tr,'hide');
                                }
                            }, false);
                        }
                    }
                }
            }
        }
        expandableTable();
    </script>
</body>
</html>
//

7 Ocak 2020

Javascript Table To CSV

function isTable(element) {
    return (element.tagName == 'TABLE' || element.tagName == 'table')
}
function downloadCsv(csv, filename) {
    if (window.Blob == undefined
        || window.URL == undefined
        || window.URL.createObjectURL == undefined) {
        alert("Your browser doesn't support Blobs");
        return;
    }
    var BOM = "\uFEFF";
    var csvFile = new Blob([ BOM + csv], { type: "text/csv;" });
    var downloadLink = document.createElement("a");
    downloadLink.download = filename;
    downloadLink.href = window.URL.createObjectURL(csvFile);
    downloadLink.style.display = "none";
    document.body.appendChild(downloadLink);
    downloadLink.click();
}

function exportToCsv(id, filename, delimiter = ';') {
    tbl = document.getElementById(id);
    if (tbl != null && isTable(tbl)) {
        var rowArr = [];
        for (var j = 0; j < tbl.rows.length; j++) {
            var r = tbl.rows[j];
            var colArr = [];
            for (i = 0; i < r.cells.length; i++) {
                var c = r.cells[i];
                colArr.push(c.innerText);
            }
            rowArr.push(colArr.join(delimiter))
        }
    }
    downloadCsv(rowArr.join('\n'), filename);
}

2 Ocak 2020

Javascript DateTime To Formatted String

function dateToFormat(date, template) { var t = template; var day = date.getDate(); if (t.indexOf('dd') > -1) { if (day < 10) day = `0${day}`; t = t.replace('dd', day); } else t = t.replace('d', day); var month = date.getMonth() + 1; if (t.indexOf('MM') > -1) { if (month < 10) month = `0${month}`; t = t.replace('MM', month); } else t = t.replace('M', month); var year = date.getFullYear(); if (t.indexOf('yyyy') > -1) t = t.replace('yyyy', year); else if (t.indexOf('yyy') > -1) t = t.replace('yyy', `${year}`.substring(1, 4)); else if (t.indexOf('yy') > -1) t = t.replace('yy', `${year}`.substring(2, 4)); else if (t.indexOf('y') > -1) t = t.replace('y', `${year}`.substring(3, 4)); var hour = date.getHours(); if (t.indexOf('HH') > -1) { if (hour < 10) hour = `0${hour}`; t = t.replace('HH', hour); } else t = t.replace('H', hour); var min = date.getMinutes(); if (t.indexOf('mm') > -1) { if (min < 10) min = `0${min}`; t = t.replace('mm', min); } else t = t.replace('m', min); var sec = date.getSeconds(); if (t.indexOf('ss') > -1) { if (sec < 10) sec = `0${sec}`; t = t.replace('ss', sec); } else t = t.replace('s', sec); return t; }

19 Aralık 2019

Enum İçin Validation

//
public class DefinedEnumAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value != null)
        {
            if (Enum.IsDefined(value.GetType(), value))
            {
                return ValidationResult.Success;
            }
            else
            {
                return new ValidationResult($"Not valid enum type {value.GetType().Name}.");
            }
        }
        return new ValidationResult("" + validationContext.DisplayName + " is required");
    }
}
public enum OrderStatus
{
    OrderReceived = 0,
    Preparing = 1,
    Printing = 2,
    Ready = 3,
    Shipped = 4
}
public class OrderDto
{
    [DefinedEnum]
    public OrderStatus OrderStatus { get; set; }

}
//

21 Ekim 2019

C# ISO Oluşturma

DiscUtils
using DiscUtils.Iso9660;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace FileCount
{
    class Program
    {
        static void Main(string[] args)
        {
            string directoryPath = @"D:\test\";
            CreateIso("test", @"C:\Users\developer\Desktop\test.iso", directoryPath, new string[] { directoryPath });
            Console.ReadKey();
        }

        public static List<string> GetAllFiles(string directoryPath)
        {
            var result = new List<string>();
            if (Directory.Exists(directoryPath))
            {
                result.AddRange(Directory.GetFiles(directoryPath));
                foreach (var dir in Directory.GetDirectories(directoryPath))
                {
                    result.AddRange(GetAllFiles(dir));
                }
            }
            return result;
        }
        static string GetSubName(string rootDirectory, string path)
        {
            if (!path.StartsWith(rootDirectory))
                new ArgumentException("Given parameters are not in same root directory!");
            var output = path.Substring(rootDirectory.Length);
            if (output[0] == '\\')
                output = output.Substring(1);
            return output;
        }
        static void CreateIso(string volumeIdentifier, string output, string rootDirectory, string[] paths)
        {
            var builder = new CDBuilder();
            builder.UseJoliet = true;
            builder.VolumeIdentifier = volumeIdentifier;
            if (!Directory.Exists(rootDirectory))
                throw new DirectoryNotFoundException("The directory not found: " + rootDirectory);

            if (!paths.All(q => q.StartsWith(rootDirectory)))
                new ArgumentException("Given parameters are not in same root directory!");
            var files = new List<string>();
            foreach (var path in paths)
            {
                var fileAttr = File.GetAttributes(path);
                if (fileAttr.HasFlag(FileAttributes.Directory))

                    files.AddRange(GetAllFiles(path));
                else files.Add(path);
            }
            foreach (var file in files.Distinct())
            {
                builder.AddFile(GetSubName(rootDirectory, file), File.ReadAllBytes(file));
            }
            builder.Build(output);
        }
        
    }
}

2 Ekim 2019

Setting Config Örneği

public class CofigurationAttribute:Attribute
    {
        public string Name { getset; }
    }
 public static class Settings
    {
        const string settingFile = "Signator.config";
        private static XDocument configuration;
        private static void LoadConfigFile()
        {
            Logger.Info($"Settings are loading from {settingFile}.");
            if (configuration == null)
                configuration = XDocument.Load(settingFile);
        }
 
        private static void LoadSettings()
        {
            LoadConfigFile();
            foreach (var property in typeof(Settings).GetProperties().Where(q => q.CustomAttributes.Any(p => p.AttributeType.Name == "CofigurationAttribute")))
            {
                Logger.Info($"Setting is reading (${property.Name})... ");
                ReadConfigFile(property);
                Logger.Info($"Setting setted ({property.Name} = {property.GetValue(null)})... ");
            }
            Logger.Info($"Settings have been readen.");
        }
        private static void ReadConfigFile(PropertyInfo property)
        {
            var custom = property.CustomAttributes.FirstOrDefault(q => q.AttributeType.Name == "CofigurationAttribute");
            var name = custom.NamedArguments.SingleOrDefault(q => q.MemberName == "Name").TypedValue.Value.ToString();
            var element = configuration.Root.Element(name);
            property.SetValue(nullelement.Value);
        }
        public static void Initialize()
        {
            Logger.Info("Settings.Initialize is running");
            LoadSettings();
            CheckForSettings();
        }
 
        
 
        private static string SetPhysicalPath(string path)
        {
            if (string.IsNullOrWhiteSpace(path))
                throw new ArgumentNullException("");
            else if (path.Length > 1 & path[1== ':')
                return path;
            else
                return Path.Combine(RootDir, path);
        }
 
 
        private static Logger m_Logger = null;
        public static Logger Logger {
            get {
                if (m_Logger == null)
                    m_Logger = LogManager.GetLogger("session");
                return m_Logger;
            }
        }
        [Cofiguration(Name = "root_directory")]
        public static string RootDir { getprivate set; }
 
        private static string m_LicenseFile = string.Empty;
        [Cofiguration(Name = "license_file")]
        public static string LicenseFile {
            get { return m_LicenseFile; }
            set {
                m_LicenseFile = SetPhysicalPath(value);
            }
        }
 
 
        private static string m_XmlSignatureConfigFile;
        [Cofiguration(Name = "xml_signature_config_file")]
        public static string XmlSignatureConfigFile {
            get { return m_XmlSignatureConfigFile; }
            set {
                m_XmlSignatureConfigFile = SetPhysicalPath(value);
            }
        }
 
 
        private static string m_SignatureOutDirectory;
        [Cofiguration(Name = "signature_out_directory")]
        public static string SignatureOutDirectory {
            get { return m_SignatureOutDirectory; }
            set {
                m_SignatureOutDirectory = SetPhysicalPath(value);
            }
        }
   }
}

8 Ağustos 2019

C# Dinamik Kod Üretimi

System.Reflection.Emit namespace, metadata ve runtime sırasında IL oluşturmak için sınıflar içerir.
Bir DynamicMethod  ve ilişkili IL garbage-collector tarafından referans olarak verilmediği zaman toplanır. Yani belleği doldurmadan dinamik olarak methodlar oluşturup durabilirsiniz.

DynamicMethod Örneği:

static void Main()
        {
            var dynMeth = new DynamicMethod("Foo", null, null, typeof(Program));
            ILGenerator gen = dynMeth.GetILGenerator();
            gen.EmitWriteLine("Hello World");
            gen.Emit(OpCodes.Ret);
            dynMeth.Invoke(null, null);

        }

Method her zaman OpCodes.Ret ile biter. Return anlamına gelir.
EmitWriteLine  metodu ILGenerator da bir dizi düşük seviyedeki opcode ları yayınlayan kısayoldur.

Aynı sonucu Emit WriteLine ile alamak için aşağıda ki gibi kodu değiştirebiliriz.

 dynMeth = new DynamicMethod("Bar", null, null, typeof(Program));
gen = dynMeth.GetILGenerator();
MethodInfo mi = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
gen.Emit(OpCodes.Ldstr, "Hello World2");
gen.Emit(OpCodes.Call, mi);
gen.Emit(OpCodes.Ret);
dynMeth.Invoke(null,null);


Public olmayan methodlara ulaşmamız için örnek:

var dynMeth = new DynamicMethod("Tar", null, null, typeof(Program));
ILGenerator gen = dynMeth.GetILGenerator();
MethodInfo privateMethod = typeof(Program).GetMethod("HelloWorld", BindingFlags.NonPublic | BindingFlags.Static);   
gen.Emit(OpCodes.Call, privateMethod);
gen.Emit(OpCodes.Ret);
dynMeth.Invoke(null, null);

Parametre ile Toplama İşlemi

using System;
using System.Reflection.Emit;

namespace ConsoleApp2
{
    class Program
    {
        delegate int BinaryFunction(int n1, int n2);
        static void Main()
        {

            var dynMeth = new DynamicMethod("Sum",
                typeof(int), //Return Type = int
                new[] { typeof(int), typeof(int) }, // Parameter Types = int, int
                typeof(Program));
            ILGenerator gen = dynMeth.GetILGenerator();
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Ldarg_1);
            gen.Emit(OpCodes.Add);
            gen.Emit(OpCodes.Ret);

            // Usage 1
            var result = (int)dynMeth.Invoke(null, new object[] { 4, 5 });
            Console.WriteLine(result);
            
            //Usage 2 // Comman Way
            BinaryFunction sumCommonWay = (BinaryFunction)dynMeth.CreateDelegate(typeof(BinaryFunction));
            result = sumCommonWay(3, 4);
            Console.WriteLine(result);

           
            Console.ReadKey();
        }

    }
}



// Yerel Değişken Ekleme ve Döngüler 
using System;
using System.Reflection.Emit;

namespace ConsoleApp2
{
    class Program
    {
        static void Main()
        {
            var dynMeth = new DynamicMethod("Sum4", typeof(int), new[] { typeof(int) }, typeof(Program));
            ILGenerator gen = dynMeth.GetILGenerator();
            Label startLoop = gen.DefineLabel(); // Declare labels
            Label endLoop = gen.DefineLabel();

            LocalBuilder i = gen.DeclareLocal(typeof(int)); // int i for index
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Stloc, i);

            LocalBuilder sum = gen.DeclareLocal(typeof(int)); // int sum for from 0 to i initial value
            gen.Emit(OpCodes.Ldc_I4,0);
            gen.Emit(OpCodes.Stloc, sum); // set value for local sum

            gen.MarkLabel(startLoop);

            gen.Emit(OpCodes.Ldc_I4, 1); // Load 10 onto eval stack
            gen.Emit(OpCodes.Ldloc, i); // Load x onto eval stack
            gen.Emit(OpCodes.Bgt, endLoop); // if (x > 10) goto endLoop


            gen.Emit(OpCodes.Ldloc, i); // Load x onto eval stack
            gen.Emit(OpCodes.Ldloc, sum); // Load x onto eval stack
            gen.Emit(OpCodes.Add);
            gen.Emit(OpCodes.Stloc, sum); // Save result back to x

            gen.Emit(OpCodes.Ldloc, i); // Load x onto eval stack
            gen.Emit(OpCodes.Ldc_I4,  -1); // Load -1 onto the stack
            gen.Emit(OpCodes.Add); // Add them together
            gen.Emit(OpCodes.Stloc, i); // Save result back to x
           

            gen.Emit(OpCodes.Br, startLoop); // return to start of loop
            gen.MarkLabel(endLoop);
            gen.Emit(OpCodes.Ldloc, sum); //
            gen.Emit(OpCodes.Ret);

            var res = (int)dynMeth.Invoke(null, new object[] { 15 });

            Console.WriteLine(res);
            Console.ReadKey();
        }

    }
}






7 Ağustos 2019

PipeStream

using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Program
    {
        /*
         
         PipeStream
         .Net 3.5 ile çıkmıştır. Bir işlemin diğer işlemlerle Windows pipes protokolü üzerinden haberleşmesini sağlar.

         İki çeşittir.
         * Anonymous pipe (daha hızlı)
            Aynı bilgisiyarda ki parnet ve child işlemleri için tek yönlü haberleşmesini sağlar.
         * Named pipe (daha esnek):
            Aynı bilgisayarda ki veya aynı Windows ağındaki farklı bilgisayarlar arasında ki keyfi işlemler arasında çift yönlü haberleşmesini sağlar.

        Bir tek bilgisayar üzerinde ki IPC(interprocess communication) haberleşme için pipe kullanmak uygundur.       

             */


        static void Main(string[] args)
        {
            //NamedPipeServerExample();
            AnonymousPipeServerExample();
            Console.ReadKey();
        }

        /*Named Pipes
         Named pipes ile taraflar aynı isim üzerinden doğrudan haberleşir. Protokol iki farklı rol tanımlar: Client ve Server
         Client ve Server arasında ki haberleşme aşağıdaki gibidir.
         NamedPipeServerStream ile server örneği oluşturulur ve WaitForConnection methodu çağrılır.
         NamedPipeClientStream ile client oluşturulur ve Connect ile bağlanılır.
         */

        static byte[] ReadMessage(PipeStream stream)
        {
            using (var ms = new MemoryStream())
            {
                var buffer = new Byte[0x1000]; // Read in 4KB blocks
                do
                {
                    ms.Write(buffer, 0, stream.Read(buffer, 0, buffer.Length));
                } while (!stream.IsMessageComplete);
                return ms.ToArray();
            }
        }

        static void NamedPipeServerExample()
        {
            string serverName = "pipedream";

            Task.Factory.StartNew(() =>
            {
                using (var server = new NamedPipeServerStream(serverName, PipeDirection.InOut, 1, PipeTransmissionMode.Message))
                {
                    server.WaitForConnection();
                    byte[] msg = Encoding.UTF8.GetBytes("Hello");
                    server.Write(msg, 0, msg.Length);
                    var resp = Encoding.UTF8.GetString(ReadMessage(server));
                    Console.WriteLine(resp);
                }
            });
            Task.Factory.StartNew(() =>
            {
                using (var client = new NamedPipeClientStream(serverName))
                {
                    client.Connect();
                    client.ReadMode = PipeTransmissionMode.Message;
                    var rec = Encoding.UTF8.GetString(ReadMessage(client));
                    Console.WriteLine(rec);
                    var msg = Encoding.UTF8.GetBytes("Hello right back!");
                    client.Write(msg, 0, msg.Length);
                }
            });
        }


        /*Anonymous pipes
         Anonymous pipe parent ve child arasında ki iki işlem arasında tek yönlü bir haberleşme sağlar.
         System çapıda isim kullanmak yerine doğrudan private handle üzerinden ayarlanır.

        1. Server AnonymousPipeServerStream örneği oluşturulur, PipeDirection In ve Out şeklinde belirtilir.
        2. Server GetClientHandleAsString ile pipe'ın kimliğini çağırırız k bunu clienta göndereceğiz.(Client oluşturulurken parametre olarak vereceğiz.)
        3. child process AnonymousPipeClientStream PipeDirection un karşıtı olarak girilir.
        4. server 2. adımda üretilen yerel handle i serbest bırakmak için DisposeLocalCopyOfClientHandle metodunu çağırırız.
        5. parent ve child processler birbirileri ile writing ve reading ile çalışır.
         */

        static void AnonymousPipeServerExample()
        {
            string clientExe = @"C:\Users\developer\Source\repos\ConsoleApp1\ClientDemo\bin\Debug\ClientDemo.exe";
            HandleInheritability inherit = HandleInheritability.Inheritable;
            using (var tx = new AnonymousPipeServerStream(PipeDirection.Out, inherit))
            using (var rx = new AnonymousPipeServerStream(PipeDirection.In, inherit))
            {
                string txID = tx.GetClientHandleAsString();
                string rxID = rx.GetClientHandleAsString();
                var startInfo = new ProcessStartInfo(clientExe, txID + " " + rxID);
                startInfo.UseShellExecute = false; // Required for child process
                Process p = Process.Start(startInfo);
                tx.DisposeLocalCopyOfClientHandle(); // Release unmanaged
                rx.DisposeLocalCopyOfClientHandle(); // handle resources.
                tx.WriteByte(100);
                Console.WriteLine("Server received: " + rx.ReadByte());
                p.WaitForExit();
            }
        }       
    }
}

///////////////
using System;
using System.IO.Pipes;

namespace ClientDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            var rxID = args[0];
            var txID = args[1];
            using (var rx = new AnonymousPipeClientStream(PipeDirection.In, rxID))
            using (var tx = new AnonymousPipeClientStream(PipeDirection.Out, txID))
            {
                Console.WriteLine("Client received: " + rx.ReadByte());
                tx.WriteByte(200);
            }

        }
    }
}