Click Here to signup for my newsletter to receive all the latest information and for your chance to win cool stuff.

Sunday, August 05, 2018

"This story caught me by surprise because I was captivated from the start."

Extract from a new 5/5 review on my novel “The Angelic Gene”. I love reading how people summarise the story in their own way. “This story caught me by surprise because I was captivated from the start. A man brings a woman into the hospital and he says the future depends on her living. As the doctor is trying to save her the man dies. Along with him so does the woman. But not before giving birth to a baby girl. The girl who is named Sophia ends up at an orphanage run by sisters. Since that is the only life she knows and she has made a very good friend named Anna, she does not want to get adopted. One day someone or something appears and wants Sophia. The sisters do not give her up and take their fate as it comes. Sophia and Anna are on the run for their lives from someone. The story is amazing and the characters are believable. While it has some supernatural ties to it, I really enjoyed reading this book and had a hard time putting it down. I must read the others to see what happens to Sophia. I do not want to give the whole story away but I really felt that this author has a great sense of imagination and story telling. I am excited about getting the others in this series” - Laura Hundrey via Goodreads. Thanks Laura, appreciate the feedback.

Sunday, March 18, 2018

Using Slim Upload with ASP .NET Core Form Post

Using Slim Image Upload with ASP.NET Core Form Post

https://pqina.nl/slim/

View Model

Public Boolean HasImage {get;set;} // Used to preload existing image and to know if image has been removed on post back.

Public string Image {get;set;} // Holder for the Image Object to come back through the form post

Public Guid Guid {get;set;} // Guid (generated on first postback but supplied back to display existing image on reloading form.  Can use same Guid to save in azure blob storage etc.

Pubic string Description {get;set;} // other field example

Public string Notes {get;set;} // other field example

View

Add hidden fields to form postback

 <input id="HasImage" asp-for="HasImage" hidden />

<input asp-for="Guid" id="Guid" hidden />

Add div class for slim.  Style as necessary for width / height or do that dynamically.  Can by dynamically scaled, and positioned.

 

<div class="slim"></slim>

Javascript for dynamically resizing inside a bootstrap panel.  SlimHolder is the panel pane.  The javascript runs on the window.resize.

 

var myWidth = $('#slimHolder').width();

var myHeight = $('#slimHolder').height();

var mySize = 0;

if (myWidth < myHeight) {

     mySize = myWidth;

}

else {

      mySize = myHeight;

}

$('.slim').height(mySize);

$('.slim').width(mySize);

var myLeftOffset = (myWidth - mySize) / 2;

if (myLeftOffset > 0) {

      $('.slim').css({ 'marginLeft': myLeftOffset + "px" });

}

else {

      $('.slim').css({'marginLeft': 0 + "px"});

}

 

Slim Initialisation

 

This can be done on page load or when the slim is bought into view. For example if the slim div is on a pane of a tab panel the initialisation can be executed when the tab pane is brought into view and a flag checked to see if the slim div has already been initialised.  The Download Image is an action of the Controller that returns the image.  If an existing image exists, the image is loaded by slim.  After load the “Image” holder is cleared to prevent the existing image loaded being posted back with the form data.

 

$('.slim').slim(

{

     didRemove: ImageRemoved,

     defaultInputName: "Image",

     label: "Drop image here or click to select file",

     ratio: "1:1",

     minSize: "100,100",

     size: "600,600",

     forceType:"jpg"

 });

 ImageInitialised = true;

 if (document.getElementById("HasImage")).checked) {

      let myImageName: string = (document.getElementById("Guid")).val();

      if (myImageName != null && myImageName.length > 0) {

      $('.slim').slim('load', `/Image/DownloadImage/${myImageName}`,

           function (error,data) {

           $('[name="Image"]').val(null);

            });

       }

   }

}

 

function ImageRemoved() {

    $('#HasImage').prop('checked', false);

}

 

Called after save successful to prevent reposting the image on subsequent saves

 

function ClearImageUpload() {

    if (ImageInitialised) {

        $('[name="Image"]').val(null);

    }

}

 

Download Image Controller

 

Gets the image from a memory stream and returns the FileStreamResult which slim reads and loads into the image.  Note it’s also possible to provide slim with a direct URL to where the image is stored rather than going via a controller if the image is physically available by a direct URL.

 

[Route("/Image/DownloadImage/{Guid:Guid}")]

public FileStreamResult DownloadImage(Guid guid)

{

     var myImageFile = File(ImageStorage.GetImageStream(guid), "image/jpeg", $"{guid}.jpg");

     return myImageFile;

 }

 

Async Form Postback Controller

In the sample given the image is stored in a memory stream but can be streamed directly to Azure Blob Storage or other stream provider to save the image.

 

[HttpPost]

[ValidateAntiForgeryToken]

public JsonResult UpdateImage(ImageViewModel image)

      {

            if (ModelState.IsValid)

            {

   if(ImageViewModel.Image!=null)

                 {

                         var myImageResult =  JsonConvert.DeserializeObject<ImageResult>(InventoryItem.Image);

                      if (myImageResult.output != null)

                            {

                                using (var myStream = new MemoryStream())

                                {

                                    myImageResult.GetImageStream().CopyTo(myStream);

                                }

                                image.HasImage = true;

                                Image.Guid = Guid.NewGuid();

                            }

                        }

                        // need to save the image view model here to keep the other associated data.

                        // Save view model back to a data model or other (not provided in example)

        // Next return back to the form ajax data that can be processed back on client side like    the new Guid, or a more advanced object indicating save state etc.

                        return Json(Image.Guid);

                    }

                }

            }

return Json(false); // save failed return back an object, or some other status that can be read in the  ajax success.

        }

 

Image Result Class

The class that the JSON Object created by slim is deserialized into.

 

        public class ImageResult

        {

            public MemoryStream GetImageStream()

            {

                byte[] bytes = Convert.FromBase64String(output.image.Substring(output.image.IndexOf(",")+1));

                return new MemoryStream(bytes);

            }

 

            public Bitmap GetBitmap()

            {

                return new Bitmap(GetImageStream());

            }

 

            public ImageResultInput input { get; set; }

            public ImageResultOutput output { get; set; }

            public class ImageResultInput

            {

                public string name { get; set; }

                public string type { get; set; }

                public int? width { get; set; }

                public int? height { get; set; }

                public int? size { get; set; }

            }

            public class ImageResultOutput

            {

                public string name { get; set; }

                public string type { get; set; }

                public int? width { get; set; }

                public int? height { get; set; }

                public string image { get; set; }

            }

        }

    }                                 

 

The javascript AJAX Form Post Back method

 

function Submit() {

        var myData = $(‘#formName}’).serializeArray();

        if (this.Validate()) {

            $.ajax({

                type: 'POST',

                url: ‘/Image/UpdateImage/’,

                data: myData,

                timeout:600000,

                dataType: 'json',

                success: (data) => { function() { ClearImageUpload(); // do whatever },

                error: (data) => { // do whatever},

                complete: () => {

                    // do whatever

                }

            }

            );

        }

    }