Azure: FTPS files to a specific deployment slot

Getting things on track, we’re now using Deployment Slots with our Azure Web Apps. Something interesting turned up when we started using a new development slot. A front end developer wanted to be able to FTPS new files directly to the slot without having to wait for the whole application to redeploy. The problem was that the FTP host and user info provided on the app and all the slots all pointed to the root of the main app. So…

How to FTPS to a specific Azure Web App Deployment Slot

  • Navigate to your app in the Azure Console
  • Select your slot
  • Click on the Get Publish Profile option on the menu
  • Get the following values from the FTP publish profile (there’s more than one publish profile in that file)
    • publishUrl
    • userName
    • userPWD

The publishUrl will be, as experienced, the same for all slots. The part you really need are the username and password. Those will default your SFTP/FTPS client to the correct home directory.

 

Thanks to Rick Rainey for this answer @ https://stackoverflow.com/questions/38729875/how-to-ftp-to-a-azure-webapp-deployment-slot-file-system 

Using Azure file storage for website file upload and download

upload utility method:

public static bool AzureFileUpload(string storageConnectionString, string shareName, HttpPostedFileBase file, string filePath, string customFileName)
 {
 bool r = false;
 try
 {
 CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageConnectionString); // CloudConfigurationManager.GetSetting("StorageConnectionString"));
 CloudFileClient fileClient = storageAccount.CreateCloudFileClient();

 CloudFileShare share = fileClient.GetShareReference(shareName);
 CloudFileDirectory root = share.GetRootDirectoryReference();

 CloudFileDirectory directory = root.GetDirectoryReference(@filePath);

 var f = file.FileName;
 if (!string.IsNullOrEmpty(customFileName))
 {
 f = customFileName;
 }

 CloudFile cloudFile = directory.GetFileReference(f);

 file.InputStream.Seek(0, SeekOrigin.Begin);
 using (var fileStream = file.InputStream)
 {
 cloudFile.UploadFromStream(fileStream);
 }
 r = true;
 }
 catch (Exception ex)
 {
 throw (ex);
 }
 return r;
 }

download utility method:

public static byte[] AzureByteFileDownload(string storageConnectionString, string shareName, string path)
{
// file.FileName.Substring(file.FileName.LastIndexOf('.'));
string fileName = path.Substring(path.LastIndexOf(@"\")).Replace(@"\", "");
path = path.Substring(0, path.LastIndexOf(@"\"));

var f = AzureFileDownload(storageConnectionString, shareName, path, fileName);

var r = new MemoryStream();
f.CopyTo(r);
return r.ToArray();
}

controller action to open the download in a new tab:

public FileContentResult DocumentDownload(int id)
{
YourBoClass _yourBoClass= new YourBoClass();

var doc = _yourBoClass.GetUploadedFile(id); // because this comes from the database

var o = Utility.FileUtility.AzureByteFileDownload(System.Configuration.ConfigurationManager.AppSettings["StorageConnectionString"],
System.Configuration.ConfigurationManager.AppSettings["ContainerName"],
path);
Response.AppendHeader("Content-Disposition", "inline; filename=" + doc.UploadName);
return File(o, MimeMapping.GetMimeMapping(doc.UploadName));
}

 

as has become normal with recent posts, commentary may or may not come later :/

Quickly see model validation error info in ASP.Net MVC

To review this.ModelState without drilling down through each item to find validation errors when using

TryUpdateModel(model, formCollection);

run this in the immediate window to quickly see model validation error info:

?ModelState.SelectMany(x => x.Value.Errors,(state, error) => $"{state.Key}:{error.ErrorMessage}")

Best followup advice — copy the results into a text editor so you don’t lose track of what needs to be fixed when you stop debugging your project :/

jQuery dialog file upload pop-up in ASP.Net MVC project

Weary of full page refresh form POSTs, Scott cobbled together a jQuery dialog file upload pop-up for an ASP.Net MVC project.

Code:

// MAIN VIEW
// --SCRIPTS

    var j = jQuery.noConflict();
    j('.fileUpload').click(function (e) {
            e.preventDefault();
            var page = $(this).attr("href");
            console.log(page);

            j('<div></div>')
                .html('<iframe style="border: 0px; " src="' + page +
                '" width="100%" height="100%"></iframe>')
                .dialog({
                    autoOpen: true,
                    modal: true,
                    height: 400,
                    width: 800,
                    title: '',
                    buttons: {
                        "Close": function () {
                            j(this).dialog("close");
                        }
                    },
                    closeText: ''
                });            
        });
        
        
// -- HTML

<a href="@Url.Action("FileUpload", "CONTROLLER", new { paramOne = item.paramOne, paramTwo = item.paramTwo })" class="fileUpload"><span class="glyphicon glyphicon-paperclip"></span></a>
                   

                   
                   
// CONTROLLER


        [HttpPost]
        public async Task<ActionResult> FileUpload(HttpPostedFileBase files, int paramOne, int paramTwo)
        {
            ViewBag.Message = "There was an error and your upload was not saved. Please contact an administrator";
            
            var r = SaveFIle(files, paramOne, paramTwo);
            if(r)
            {
                ViewBag.Message = "File Uploaded. Upload another or click Close below";
            }
            ViewBag.paramOne = paramOne;
            ViewBag.paramTwo = paramTwo;
            return PartialView("_Upload");
        }
        
        
// PARTIAL VIEW "_Upload.cshtml"



@ViewBag.Message

<form method="post" enctype="multipart/form-data" action="/CONTROLLER/FileUpload">
    <input type="hidden" name="paramOne" id="paramOne" value="@ViewBag.paramOne" />
    <input type="hidden" name="paramTwo" id="paramTwo" value="@ViewBag.paramTwo" />
    <div class="form-group">
        <div class="col-md-10">
            <p>Upload one or more files using this form:</p>
            <input type="file" name="files" multiple />
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-10">
            <input type="submit" value="Upload" />
        </div>
    </div>
</form>

Commentary:

(to follow. maybe. and a screen-shot of the clean-ed up version. maybe. and need to break that up into other code blocks. just don’t want to hunt for it later if I re-use it)

C# Random String Generator

Generate a string of random alphanumeric characters in C#. Needed this for naming. NOT FOR USE WITH SECURITY! Need to find the Stack Overflow post this is based on…as usual, it wasn’t the accepted answer, but it was the one I liked that met my needs…

        private string GetRandom(int len)
        {
            var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            var stringChars = new char[len];
            var random = new Random();

            for (int i = 0; i < stringChars.Length; i++)
            {
                stringChars[i] = chars[random.Next(chars.Length)];
            }

            var finalString = new String(stringChars);
            return finalString;
        }

Especially cool because you can control what characters are used in your random string…

Adding type-ahead to a dynamically generated text box

Needed to add type-ahead to a field on a dynamically created form. Backstory: click the button to add another field group. One of the fields needed to be a type-ahead. So, we have a whole javascript function to add the form:

$('#addit').on('click', function () {
 id = getId(); // an id string based on the current time
 newHtml = updateHtml(id); // the form in on long var
 $('#form').append(newHtml);
 // console.log(id);
 });

And this is in the $(document).ready() function to handle the type-ahead:

        var autocomp_opt = {
            source: function (request, response) {
                $.ajax({
                    url: "/Controller/GetTypeAhead",
                    dataType: "json",
                    type: "post",
                    data: {
                        maxRows: 15,
                        term: request.term
                    },
                    success: function (data) {
                        console.log(data);
                        response($.map(data, function (item) {
                            return {
                                return item;
                            }
                        }));
                    }
                })
            },
                select: function (e, i) {
                    $("#divName").val(i.item.val);
                },
                minLength: 3,
        };

        $('body').on('focus', '.type', function () {
            $(this).autocomplete(autocomp_opt).on('blur', function () { $(this).autocomplete('destroy') });
        });

Obviously I need a code editor plugin or need to remember the correct way to add code snippets to a post :-/

See http://stackoverflow.com/questions/26498602/enabling-jquery-autocomplete-on-dynamically-created-input-fields . The zero rated answer at the bottom is actually what worked for me.

Here’s a line I forgot about in my controller that I want to remember:

public ActionResult GetTypeAhead(string term, int maxRows)
        {
            var r = new List<SearchTypeAheadEntity>
            {
               new SearchTypeAheadEntity {val="1", label="Text One"},
               new SearchTypeAheadEntity {val="2", label="Second Text"},
               new SearchTypeAheadEntity {val="3", label="Third Value"},
               new SearchTypeAheadEntity {val="4", label="Fourth Code"}
            };
            var val = (from n in r where n.label.ToLower().StartsWith(term.ToLower()) select new { n.label });
            return Json(val, JsonRequestBehavior.AllowGet);
        }

Here’s the updateHtml() function for my own future ref:

function updateHtml(id)
 {
 return '<form id=form' + id + ' method=post action=/mvcController/mvcMethod><input type=text name=name' + id + ' id=name' + id + '><input type=text class=type name=type' + id + ' id=type' + id + '>@Html.AntiForgeryToken()<input type=submit class=skipIt id=submit'+id+'></form>';
 }


Be gentle with the EDMX file…

The worst of my battles with the EDMX file seem to be over. I wish I could remember how I resolved the context name getting lost. If I run into that again, I’ll be sure to post the fix. Here are some other quick notes…

If you update a stored proc, remove it from the following locations, save, and then re-add:

  1. 1st place- Under Complex Types-> as MyStoreProc_result
  2. 2nd Place- Under Function Imports -> as MyStoreProc
  3. 3rd Place – Under Stored Procdures/ Functions -> as MyStoreProc

See http://stackoverflow.com/questions/18038405/stored-procedures-and-updating-edmx

Updating a table or a view just plain doesn’t work. Delete and re-add those, too.

Finding objects on the design surface:

Click an empty spot in the surface and use the dropdown in the properties window to scroll to the object you’re looking for. It will be highlighted on the surface once you select it from the list. It still may not be easy to see, but at least you don’t have to hunt as hard for it.

dBase CYYMMDD integer to usable date

Working on some SQL queries against a database running on an IBM iSeries recently, I had to deal with a numeric date format that (allegedly) makes it easier to compare dates. Right. Right? Here are a couple of select clauses to turn that CYYMMDD integer value into something you can actually use…and read:

-- Convert to YYYY-MM-DD
DATE((INT(NULLIF(nullif(FIELD_NAME,999999),0)/10000)+1900)||'-'||
(INT(MOD(NULLIF(nullif(FIELD_NAME,999999),0),10000)/100))||'-'||
(INT(MOD(NULLIF(nullif(FIELD_NAME,999999),0),100)))) AS "YYYY-MM-DD DATE"

-- I forget where this one was going...
-- Convert CYYMMDD to YYYY-MM-DD and subtract (current date + 60) from it
DAYS(DATE((INT(NULLIF(nullif(FIELD_NAME,999999),0)/10000)+1900)||'-'||
(INT(MOD(NULLIF(nullif(FIELD_NAME,999999),0),10000)/100))||'-'||
(INT(MOD(NULLIF(nullif(FIELD_NAME,999999),0),100))))) 
-DAYS(CURRENT DATE + 60 DAYS) AS "EXPIRES IN X DAYS"

Read or write to an XML datasource with C#

Quick post with a code snippet I was looking for to read or write to an XML datasource with C#. YMMV, so be sure to add some error checking 😉

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Xml;
 
namespace XMLConfig
{
    public class dataAccess
    {
        public static DataSet getData(string fileLocation)
        {
            DataSet ds = new DataSet();
            ds.ReadXml(fileLocation);
            return ds;
        }
 
        public static bool setData(DataSet dx, string fileLocation)
        {
            bool status = false;
            dx.WriteXml(fileLocation);
            return status;
        }
    }
}
// this is some code to add or edit items in the dataset. These come from a gridview but whatevs
        public void confirmButton_Click(object sender, EventArgs e)
        {
            if (rowNumberField.Value != "new")
            {
                ds.AcceptChanges();
                int rowNumber = Convert.ToInt16(rowNumberField.Value);
                GridView1.Rows[rowNumber].Cells[1].Text = editChoice.Text;
                GridView1.Rows[rowNumber].Cells[2].Text = editValue.Text;
                GridView1.Rows[rowNumber].Cells[3].Text = editTemplate.Text;
                GridView1.Rows[rowNumber].Cells[4].Text = selectVisible.SelectedValue;
 
                int x = 0;
                int y = 1;
                for (x = 0; x < ds.Tables[0].Rows.Count; x++)
                {
                    for (y = 1; y < ds.Tables[0].Columns.Count + 1; y++)
                    {
                        ds.Tables[0].Rows[x].SetField<string>(y - 1, GridView1.Rows[x].Cells[y].Text.Trim());
                    }
                }
                updateDataSet();
            }
            else
            {
                // DataRow r = new DataRow();
                DataRow r;
 
                string[] a;
                a = new string[4];
                a[0] = editChoice.Text;
                a[1] = editValue.Text;
                a[2] = editTemplate.Text;
                a[3] = selectVisible.SelectedValue;
 
                // r.ItemArray = a.ToArray();
 
                r = ds.Tables[0].NewRow();
                r.ItemArray = a.ToArray();
 
                ds.Tables[0].Rows.Add(r);
 
                updateDataSet();
 
                GridView1.DataBind();
            }
        }