Detecting image type code snip0 Reacties

I need this type of code often, since you don’t want to asume that a file extension, e.g. .jpeg really is jpeg. It just as well could be a malware file. Also, in combination with getting height and width, this tool does more than the other snips. Enjoy!

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using System;
using System.IO;
using System.Threading.Tasks;

namespace ADCCure
{
     public static class ImageHelper
     {
         /// <summary>
         /// detects image type from binary data
         /// </summary>
         /// <param name="blob">must be supplied</param>
         public async static Task<(int width, int height, string mimeType)> DetectImageType(this byte[] blob)
         {
             if (blob == null)
             {
                 throw new ArgumentNullException(nameof(blob));
             }
             var config = new Configuration();

            var formatsDetectionsWanted = new IImageFormatDetector[] { new JpegImageFormatDetector(), new PngImageFormatDetector(), new SixLabors.ImageSharp.Formats.Gif.GifImageFormatDetector(), new SixLabors.ImageSharp.Formats.Tga.TgaImageFormatDetector()};
             var decodersWanted = new (IImageDecoder decoder, IImageFormat format)[] {
                 (new JpegDecoder(), JpegFormat.Instance),
                 (new PngDecoder(), PngFormat.Instance),
                 (new GifDecoder(), GifFormat.Instance),
                 (new TgaDecoder(), TgaFormat.Instance) };

            IImageFormat detected = default;
             foreach (var fmt in formatsDetectionsWanted)
             {
                 config.ImageFormatsManager.AddImageFormatDetector(fmt);
                 if (detected == null)
                 {
                     detected = fmt.DetectFormat(blob);
                 }
             }
             foreach (var (decoder, format) in decodersWanted)
             {
                 config.ImageFormatsManager.SetDecoder(format, decoder);
             }
             if (detected != null)
             {
                 var image = await Image.LoadAsync(config, new MemoryStream(blob));

                return (image.Width, image.Height, detected.DefaultMimeType);
             }
             return default;
         }
     }
}

c# Detect Image type and height and width0 Reacties

Often, I need this code, because you never can assume mimetype (which is, image/jpeg image/png etc) because the extension says so.

This piece of code might help you too. It uses the well known SixLabors library.


using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using System;
using System.IO;
using System.Threading.Tasks;

namespace ADCCure
{
     public static class ImageHelper
     {
         /// <summary>
         /// detects image type from binary data
         /// </summary>
         /// <param name="blob">must be supplied</param>
         public async static Task<(int width, int height, string mimeType)> DetectImageType(this byte[] blob)
         {
             if (blob == null)
             {
                 throw new ArgumentNullException(nameof(blob));
             }
             var config = new Configuration();

            var formatsDetectionsWanted = new IImageFormatDetector[] { new JpegImageFormatDetector(), new PngImageFormatDetector(), new SixLabors.ImageSharp.Formats.Gif.GifImageFormatDetector(), new SixLabors.ImageSharp.Formats.Tga.TgaImageFormatDetector()};
             var decodersWanted = new (IImageDecoder decoder, IImageFormat format)[] {
                 (new JpegDecoder(), JpegFormat.Instance),
                 (new PngDecoder(), PngFormat.Instance),
                 (new GifDecoder(), GifFormat.Instance),
                 (new TgaDecoder(), TgaFormat.Instance) };

            IImageFormat detected = default;
             foreach (var fmt in formatsDetectionsWanted)
             {
                 config.ImageFormatsManager.AddImageFormatDetector(fmt);
                 if (detected == null)
                 {
                     detected = fmt.DetectFormat(blob);
                 }
             }
             foreach (var (decoder, format) in decodersWanted)
             {
                 config.ImageFormatsManager.SetDecoder(format, decoder);
             }
             if (detected != null)
             {
                 var image = await Image.LoadAsync(config, new MemoryStream(blob));

                return (image.Width, image.Height, detected.DefaultMimeType);
             }
             return default;
         }
     }
}

c# Detect Image type and height and width0 Reacties

Often, I need this code, because you never can assume mimetype (which is, image/jpeg image/png etc) because the extension says so.

This piece of code might help you too. It uses the well known SixLabors library.


using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using System;
using System.IO;
using System.Threading.Tasks;

namespace ADCCure
{
     public static class ImageHelper
     {
         /// <summary>
         /// detects image type from binary data
         /// </summary>
         /// <param name="blob">must be supplied</param>
         public async static Task<(int width, int height, string mimeType)> DetectImageType(this byte[] blob)
         {
             if (blob == null)
             {
                 throw new ArgumentNullException(nameof(blob));
             }
             var config = new Configuration();

            var formatsDetectionsWanted = new IImageFormatDetector[] { new JpegImageFormatDetector(), new PngImageFormatDetector(), new SixLabors.ImageSharp.Formats.Gif.GifImageFormatDetector(), new SixLabors.ImageSharp.Formats.Tga.TgaImageFormatDetector()};
             var decodersWanted = new (IImageDecoder decoder, IImageFormat format)[] {
                 (new JpegDecoder(), JpegFormat.Instance),
                 (new PngDecoder(), PngFormat.Instance),
                 (new GifDecoder(), GifFormat.Instance),
                 (new TgaDecoder(), TgaFormat.Instance) };

            IImageFormat detected = default;
             foreach (var fmt in formatsDetectionsWanted)
             {
                 config.ImageFormatsManager.AddImageFormatDetector(fmt);
                 if (detected == null)
                 {
                     detected = fmt.DetectFormat(blob);
                 }
             }
             foreach (var (decoder, format) in decodersWanted)
             {
                 config.ImageFormatsManager.SetDecoder(format, decoder);
             }
             if (detected != null)
             {
                 var image = await Image.LoadAsync(config, new MemoryStream(blob));

                return (image.Width, image.Height, detected.DefaultMimeType);
             }
             return default;
         }
     }
}

ASP.NET Core Attribute to Rate limite an Endpoint0 Reacties

Untitled

An easy codesnippet which might help you to avoid an endpoint being DDOS-ed. It uses MemoryCache, which of course also could be configured to use e.g. a Redis backed, but now it uses a hash table with an int key and a boolean, so it is very lightweight and it works in a fast-fail principle (instead of consulting backend storage first). Also keep in mind, that it works –in memory- so it does not protect an array of endpoints.


Usage:


      [HttpGet("myurl")]
        [ThrottleFilter(Name= "myurl", Milliseconds = 5*1000 )]
        public async Task<ActionResult> MyUrl()





using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Net;

namespace AdcCure.ActionFilters
{
     /// <summary>
     /// Decorates any MVC route that needs to have client requests limited by time.
     /// </summary>
     /// <remarks>
     /// Uses the current Microsoft.Extensions.Caching.Memory extensions
     /// to store each client request to the decorated route, using the least amount of memory requirements possible
     /// </remarks>
     [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
     public class ThrottleFilterAttribute : ActionFilterAttribute
     {

        /// <summary>
         /// A unique name for this Throttle.
         /// </summary>
         /// <remarks>
         /// We'll be inserting a Cache record based on this name and client IP, e.g. "Name-192.168.0.1"
         /// Cache is 'hashed' so the memory table is int (key), bool (disallow)
         /// The entry only exists for [Milliseconds] so is a minimal resource requirement
         /// </remarks>
         public string Name { get; set; }

        /// <summary>
         /// The number of Milliseconds clients must wait before executing this decorated route again.
         /// </summary>
         public int Milliseconds { get; set; }

        /// <summary>
         /// A text message that will be sent to the client upon throttling.  You can include the token {n} to
         /// show this.Seconds in the message, e.g. "Wait {n} seconds before trying again".
         /// </summary>
         public string Message { get; set; }

        public override void OnActionExecuting(ActionExecutingContext c)
         {
             var services = c.HttpContext.RequestServices;
             if (!(services.GetService(typeof(IMemoryCache)) is IMemoryCache memCache))
             {
                 throw new InvalidOperationException($"{this.GetType()} configure a memory cache in startup");
             }
             var logger = default(ILogger);
             var loggerInst = services.GetService(typeof(ILoggerFactory));
             if (loggerInst is ILoggerFactory factory)
             {
                 logger = factory.CreateLogger<ThrottleFilterAttribute>();
             }

            var headers = c.HttpContext.Request.Headers;
             var testProxy = headers.ContainsKey("X-Forwarded-For");
             var ipStream = new MemoryStream(512);
             var ip = default(IPAddress);
             if (testProxy)
             {
                 IPAddress.TryParse(headers["X-Forwarded-For"], out ip);
             }
             if (ip == null)
             {
                 ip = c.HttpContext.Connection.RemoteIpAddress;
             }
             if (!string.IsNullOrEmpty(Name))
             {
                 var stringBf = System.Text.Encoding.UTF8.GetBytes(Name);
                 ipStream.Write(stringBf, 0, stringBf.Length);
             }
             var bytes = ip.GetAddressBytes();
             ipStream.Write(bytes, 0, bytes.Length);
            
             var key = ComputeHash(ipStream.ToArray());

            memCache.TryGetValue(key, out bool forbidExecute);

            memCache.Set(key, true, new MemoryCacheEntryOptions() { AbsoluteExpirationRelativeToNow = TimeSpan.FromMilliseconds(Milliseconds) });
             if (logger != null)
             {
                 logger.LogDebug("key for Throttle {0}", key);
             }
             if (forbidExecute)
             {
                 if (string.IsNullOrEmpty(Message))
                 {
                     Message = $"You may only perform this action every {Milliseconds}ms.";
                 }
                 if (logger != null)
                 {
                     logger.LogWarning("ip {0}, route {1} was denied execute at {2}", ip, Name ?? "unknown", DateTimeOffset.Now);
                 }
                 c.Result = new ContentResult { Content = Message, ContentType = "text/plain" };
                 // see 409 - http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
                 c.HttpContext.Response.StatusCode = StatusCodes.Status409Conflict;
             }
         }
         /// <summary>
         /// fast method to calc a byte array to the same hash no matter on which process it is performed
         /// </summary>
         /// <param name="data"></param>
         private static int ComputeHash(byte[] data)
         {
             unchecked
             {
                 const int p = 16777619;
                 int hash = (int)2166136261;
                 var len = data.Length;
                 for (int i = 0; i < len; i++)
                     hash = (hash ^ data[i]) * p;

                hash += hash << 13;
                 hash ^= hash >> 7;
                 hash += hash << 3;
                 hash ^= hash >> 17;
                 hash += hash << 5;
                 return hash;
             }
         }
     }
}

Wow a NEW feature in Notepad for Windows (10)0 Reacties


I can’t believe MS really did this to the dinosaur of all applications! After more than 20 years, using Windows notepad for quick scrap edits, I found out that notepad has a new item in it’s menu ‘edit’.


Really? Yes, you don’t believe me? Try it! Alt-E It says: “Search with Bing”.

You understand, I immediately un-installed sublime edit and notepad++. ! Smile



Annotation 2020-01-28 115446

PowerShell script to upload a list of JSON files from a folder0 Reacties


Just an example.


Get-ChildItem ($PSScriptRoot + '\package') -Filter *.json |
Foreach-Object {
     $headers = @{}
     $headers['host'] = 'localhost:8080'
     $content = Get-Content $_.FullName
     $x = $content | ConvertFrom-Json
     $headers["Content-Length"] = $_.Length
     $id = $x.id
     $url = '
http://localhost:8080/' + $x.resourceType + '/' + $id
     if ($x.resourceType)
     {
         try
         {
             $response = Invoke-WebRequest -URI $url -Method Put -InFile $_.FullName -ContentType 'application/fhir+json' -Headers $headers
             Write-Host $url  ' = success type='  $x.resourceType
         }
         catch [System.Net.WebException] {
             Write-Host ($_ )

            Write-Host $url
      
         }
     }
}

Upgrade to ASP.NET Core 3.0 considerations0 Reacties

Before you change .NET Core framework from 2.x to 3.0/3.1, expect for those solutions, issues. More than 1.x to 2.x.

I’ll mention some things to consider.


JSON Serialisation

JSON serialisation is up to 4 times faster due to Microsoft implementing utf8 streams, which is more efficient. Newtonsoft now is an ‘option’.

However, if you have REST Endpoints that work with JObject as argument will not simply work. The suggested JsonElement alternative by MS will require you to do inefficient things. If this is the case, set Newton as default, until .NET supports JsonDocument instead of JObject.

If your POCO objects, used by your REST Api, have self-refering references, System.Text.Json.JsonSerializer cannot handle this.

You need this in startup:

      services.AddNewtonsoftJson(options =>
                    {
                        var opt = options.SerializerSettings;                
                        opt.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                    })


Synchronous operations are disallowed

If any of your code is still using Xml serialisation, like using XDocument, this will fail if it uses the synchoneous version. Like ‘XDocument.Save’  or even ‘ XDocument.SaveAsync’ That fails with “Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead”


Fix that with:

var xmlWriter = XmlWriter.Create(context.HttpContext.Response.Body, settings: new XmlWriterSettings { Async = true });

await Xml.WriteToAsync(xmlWriter, default);
  await xmlWriter.FlushAsync();


Dont forget to flush. It took me 1 hour to find out. (Yep, no unit tests, extern solution).

However, some libraries are out of your control, so you might need these too.


services.Configure(options =>
             {
                 options.AllowSynchronousIO = true; //to get metaweblogcontroller working
             });
             services.Configure(options =>
             {
                 options.AllowSynchronousIO = true;
             });

UrlHelper

If you work with Razor, you might be using UrlHelper. In previous .NET core versions you could inject IUrlHelper using IActionContextAccessor. You need an extra line using IUrlHelperFactory.

services.AddScoped(x => {
                var actionContext = x.GetService().ActionContext;
                var factory = x.GetRequiredService();
                return factory.GetUrlHelper(actionContext);
            });


    PowerShell script to upload a file to a remote FTP server0 Reacties

    I needed a simple script to upload a file remotely to an FTP server, and found a script on StackOverflow.

    However, the script could use some improvements such as SSL. Here it is. Good luck with it

    $ftp = [System.Net.WebRequest]::Create("ftp://ftp.yourserverblahblah.com/public/" + $args[0])
    $ftp = [System.Net.FtpWebRequest]$ftp #cast
    $ftp.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile #"STOR"
    $ftp.Credentials = new-object System.Net.NetworkCredential("someuser","incrediblepassword****")
    $ftp.UseBinary = $true
    $ftp.UsePassive = $true
    $ftp.EnableSsl = $true

    $fullPathIncFileName = $MyInvocation.MyCommand.Definition

    $currentExecutingPath = [System.IO.Path]::GetDirectoryName($fullPathIncFileName)
    $file = [System.IO.Path]::Combine($currentExecutingPath, $args[0])
    Write-Host "Going To Copy " + $file
    # read in the file as a stream.
    $content = [System.IO.File]::OpenRead($file)

    # get the request stream, and copy the bytes into it
    $rs = $ftp.GetRequestStream()
    $content.CopyTo($rs)
    $rs.Close()
    $content.Close()

    An easy Taghelper to make an element ‘active’ when clicked using Razor.0 Reacties

    Still using backend HTML logic.

    ASP.NET Core makes things a lot more easier for us, backend developers. Though, accent today, is more on frontend development, still, for reasons of security for instance, backend state management is still used.

    Now take a look at this tiny gem, a TagHelper.

    A ‘which menu has been clicked-set-active-helper’

    What it does, basically, is checking if a

  • element has an attribute activecheck. If so, it detects which ‘action-route’ was executed/is executing and if the name matches, it adds class=”active”. So the output will be  e.g.
  • active”>
  • e.g. in the Razor View I have:


                                           <li activecheck="true" data-menu="Index" >
                                                <a asp-controller="Home" asp-action="Index">Homea>
                                           

      I had to add a ‘data-menu’ attribute, because Taghelpers, can not, as far as I found, parse the raw Razor Markup, when using ‘GetChildContentAsync()’  for instance, it only gets the HTML output that’s already there, without Razor markup. So, I cannot parse the child anchor and retrieve asp-acction=”Index”.
      Therefore, I specify it again using data-menu=”Index”. Note, this is removed later by the taghelper.

      using Microsoft.AspNetCore.Html;
      using Microsoft.AspNetCore.Mvc.Controllers;
      using Microsoft.AspNetCore.Mvc.Infrastructure;
      using Microsoft.AspNetCore.Razor.TagHelpers;

      namespace ladidah.TagHelpers
      {
          [HtmlTargetElement("li", Attributes = "activecheck")]
          public class LiActiveHelper: TagHelper
          {
              public bool activecheck { get; set; }
              private readonly string menu;
              public LiActiveHelper(IActionContextAccessor httpContext)
              {
                  var currentRoute = (ControllerActionDescriptor)httpContext.ActionContext.ActionDescriptor;
                  menu = currentRoute.ActionName;
              }
              public override void Process(TagHelperContext context, TagHelperOutput output)
              {
                  if (activecheck)
                  {
                      var dataMenu = output.Attributes["data-menu"];
                   
                       if (dataMenu != null && dataMenu.Value is HtmlString str && str.Value == menu)
                      {
                          output.Attributes.RemoveAll("activecheck");
                          output.Attributes.RemoveAll("data-menu");
                          if (!output.Attributes.ContainsName("class"))
                          {
                              output.Attributes.SetAttribute("class", "active");
                          }
                      }               
                  }          
              }
          }
      }

      To activate this taghelper, I had to add the following line in my _ViewImports.cshtml file

      @addTagHelper ladidah.TagHelpers.LiActiveHelper, ladidah

      Benefit of IoC in ASP.NET Core.

      In my ConfigureServices method, in startup.cs I had to add the following line, in order to be able to get the action context of the current MVC Controller.

      public void ConfigureServices(IServiceCollection services)
             {

      // code removed for readability

        services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();

      }

      I hope you find this snippet useful.

    Finally OData 7.x supports and ASP.NET Core 2.x0 Reacties

    Finally we can create OData (v4) services using ASP.NET Core.

    My first impression, it’s ok, plus it has extra features.

    Use my startup project, on Github as a sample. (It’s tricky to forget to enable features like Filter, otherwise you’ll and up with :

    value":"The query specified in the URI is not valid. The property 'Id' cannot be used in the $filter query option."}

    So, this is the Configure section

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
           {
               if (env.IsDevelopment())
               {
                   app.UseDeveloperExceptionPage();
               }
               var builder = new ODataConventionModelBuilder(app.ApplicationServices);
               builder.EntitySet("Cars");
          
               app.UseMvc(routeBuilder =>
               {
                   routeBuilder.Count().Filter().OrderBy().Select().MaxTop(null).Expand();
                   routeBuilder.MapODataServiceRoute("ODataRoute", "odata", builder.GetEdmModel());
                   // Work-around for #1175

                   routeBuilder.EnableDependencyInjection();
               } ) ;
           }

    To get PATCH and POST working, we need the [FromBody] Attribute like here

    public async Task Post([FromBody] Car newCar)

     

    The sample, is downloadable here (ASP.NET-Core-With-Odata-7)