European ASP.NET MVC Hosting

BLOG about Latest ASP.NET MVC Hosting and Its Technology - Dedicated to European Windows Hosting Customer

ASP.NET MVC 6 Hosting - HostForLIFEASP.NET :: Understanding Separation Of Concern in ASP.NET MVC

clock February 22, 2021 06:01 by author Peter

What is Separation of Concern?
Wikipedia says “In computer science, separation of concerns (SoC) is a design principle for separating a computer program into distinct sections, such that each section addresses a separate concern. A concern is a set of information that affects the code of a computer program.”

As said concern is a set of information, in our application concern is known as modules or a set of responsibility, we use this principle to separate application module to manage scalable applications.

You can also think of separation the same as how we use layers in our application as follows:


However we can implement different tiers for databases as well.

The above architecture can be followed in any web or native (desktop) application, in order to use separation of concern.

How separation of concern in ASP.NET

A couple of years ago, Microsoft came up with ASP.NET MVC which is a superset of ASP.NET (now ASP.NET web form). Since before ASP.NET MVC there was Spring (JAVA), Ruby on Rail frameworks and may be others has already implemented MVC architecture.

ASP.NET MVC adds SoC for web (http) and separate Model (business), View(User Interface) and Controller (Processing data to view or vice versa), it gives responsibility to Model, View, Controller as follows :


You may have seen the above diagram in many articles. Herethe model is responsible to handle business logic, don’t get it confused with ViewModel as ViewModel are simple classes in ASP.NET MVC to bind strongly typed views.

Flexibility and its violation of SoC in ASP.NET MVC
As a ASP.NET MVC developer I feel it’s quite flexible to work with MVC as it’s a framework with extensibility as we can implement our own principles if required.

MVC framework uses loose coupling (another form of SoC) for every concern (modules). It’s recommended to use Model for business logic, controller for processing incoming requests and views to display information to end user.

But the actual problem is due to flexibility of ASP.NET MVC and it’s easy to violate these principles.

Examples of violation of MVC principle:

    Using ViewBag or ViewData for passing data from controller to view:
        // contoller  
        public ActionResult Index()   
        {  
                ViewBag.EmployeeData = getEmplyees(x => x.DOB > DateTime.Now);  
            }  
            // view  
        foreach(var employee in ViewBag.EmployeeData)  
        {  
            // using data  
        }  

    Above line of code doesn’t restrict developer, but it violates principle to use ViewModel to display data in view.

    Using business logic in controller:
        Public ActionResult Save(Employee model)  
        {  
            If(ModelState.IsValid)   
            {  
                _dbContext.Employees.Add(model)  
            }  
            Return RedirectToAction(“Success”);  
        }  

    Using above code, its violation of SRP because controller is having database logic to save information.

    Using business logic in view:
        @if(user.Role == ”Admin”)  
        {  
            //  
        }  
        Else   
        {  
            //  
        }  

    Using this we are using business logic in view which is only responsible to display information.

Apart from these, there area lot of code snippets you can find in your ASP.NET MVC project as well as online communities.

Recommendations

Where to put business logic:
It’s recommended to use a Service layer to implement business logic in your application as follows:
    public class EmployeeService   
    {  
        IRepository _employeeRepository;  
        public EmployeeService(IRepository employeeRepository)   
        {  
            this._employeeRepository = employeeRepository;  
        }  
        public IEnumeratble < Employee > GetEmplyee(int id)   
        {  
            return _employeeRepository.FindBy(x => x.ID == id).FirstOrDefault();  
        }…………..  
    }  


Repository pattern is a well known pattern for data access, here is a sample:
    public class Repository < T > : IRepository < T > where T: class   
    {  
        private DbContext Context;  
      
        public Repository(DbContext ctx)   
        {  
            Context = ctx;  
        }  
      
        public virtual IQueryable < T > GetAll()   
        {  
            IQueryable < T > query = Context.Set < T > ().AsQueryable();  
            return query;  
        }  
        public IQueryable < T > FindBy(System.Linq.Expressions.Expression < Func < T, bool >> predicate)   
        {  
            IQueryable < T > query = Context.Set < T > ().Where(predicate);  
            return query;  
        }
      
    }  


Repository can be wrapped with a unit of work to save final changes all together. Here is sample unit of work interface which can be implemented for convenience, however it’s not required.
    public interface IUnitOfWork  
    {  
        IRepository < TEntity > GetRepository < TEntity > () where TEntity: class;  
        void Save();  
    }  


And finally we can inject (using DI) service in controller to use business objects.
    public class EmployeeContoller   
    {  
        IService _employeeService;  
        Public EmployeeContoller(IService employeeService)   
        {  
            _employeeService = employeeService;  
        }…………  
    }  

I hope readers will avoidthe  above mentioned mistakes while working with ASP.NET MVC to deliver scalable applications.



ASP.NET MVC 6 Hosting - HostForLIFEASP.NET :: View Without Controller Action in MVC

clock February 19, 2021 12:18 by author Peter

In this quick article you will learn how a view can be rendered without its native Controller Action method.

Why do we need this?
Let's look at the following image.


In the image above, you can see that for each view we have a matching controller action. Each of these actions contains a single line of code. In fact, each of these actions contains exactly the same line of code. And this is completely unnecessary. Imagine what you will do when you have hundreds or thousands of views. Will you create hundreds or thousands of controller actions? Of course not, then how can we fix it?

In the MVC Framework, the controller class includes a method, HandleUnknownAction(), that executes whenever we attempt to invoke an action (or when we request a view that has no matching action method) on a controller that does not exist.


Now we are taking advantage of the HandleUnknownAction() method to render views even when a corresponding controller method does not exist.

In the image above you can see we don't have Post5.cshtml, so when I tried to access the Post5.cshtml view, it shows the following error.


To fix this issue, we can use a simple try-catch block and redirect the user on a PageNotFound view; here's how.


 



ASP.NET MVC 6 Hosting - HostForLIFE :: Upload Large Files To MVC / WebAPI Using Partitioning

clock February 8, 2021 09:26 by author Peter

Sending large files to an MVC/Web-API Server can be problematic. This article is about an alternative. The approach used is to break a large file up into small chunks, upload them, then merge them back together on the Server via file transfer by partitioning. The article shows how to send files to an MVC Server from both a webpage using JavaScript, and a Web-form httpClient, and can be implemented using either MVC or Web API.

In my experience, the larger the file you need to upload to a website/API, the bigger the potential problems you encounter. Even when you put the right settings in place, adjust your web.config, make certain you use the right multiplier for maxRequestLength and maxAllowedContentLength and of course don't forget about executionTimeout (eek!), things can still go wrong. Connections can fail when the file is *almost* transferred, servers unexpectedly (Murphy's law) run out of space, etc., the list goes on. The diagram below demonstrates the basic concept discussed in this article.

Background
The concept for this solution is very simple. The attached code works (I have it started in production), and can be improved by you in many ways. For example, for the purposes of this article the original large file is broken into app. 1mb chunks, and uploaded to the server sequentially, one chunk at a time. This could, for example, be made more efficient by threading, and sending chunks in parallel. It could also be made more robust by adding fault tolerance, auto-resume into a rest-api architecture etc. I leave you to implement these features yourself if you need them.

The code consists of two parts - the initial file-split/partitioning into chunks, and the final merge of the chunks back into the original file. I will demonstrate the file-split using both C# in a web-form, and JavaScript, and the file-merge using C# server-side.

File split
The concept of splitting a file is very basic. We transverse the file in a binary stream, from position zero, up to the last byte in the file, copying out chunks of binary data along the way and transferring these. Generally we set an arbitrary (or carefully thought out!) chunk size to extract, and use this as the amount of data to take at a time. Anything left over at the end is the final chunk.

In the example below, a chunk size of 128b is set. For the file shown, this gives us 3 x 128b chunks, and 1 x 32b. In this example there are four file chunks resulting from the split and to transfer to the server.

C# File Split
The accompanying demo "WinFileUpload" is a simple Windows forms application. Its sole function is to demonstrate splitting a sample large file (50 MB) in C#, and using a HTTPClient to post the file to a web-server (in this case, an MVC Server).

For this C# example, I have a class called Utils  that takes some input variables such as maximum file chunk size, temporary folder location, and the name of the file to split. To split the file into chunks, we call the method "SplitFile". SplitFile works its way through the input file and breaks it into separate file chunks. We then upload each file chunk it using "UploadFile".
Utils ut = new Utils();  
ut.FileName = "hs-2004-15-b-full_tif.bmp"; // hard coded for demo  
ut.TempFolder = Path.Combine(CurrentFolder, "Temp");  
ut.MaxFileSizeMB = 1;  
ut.SplitFile();  

foreach (string File in ut.FileParts)  
{  
UploadFile(File);  
}  
MessageBox.Show("Upload complete!");  


The file upload method takes an input file-name, and uses a HTTPClient to upload the file. Note the fact that we are sending MultiPartFormData to carry the payload.
public bool UploadFile(string FileName)  
{  
bool rslt = false;  
using (var client = new HttpClient())  
{  
using (var content = new MultipartFormDataContent())  
{  
 var fileContent = new   ByteArrayContent(System.IO.File.ReadAllBytes(FileName));  
 fileContent.Headers.ContentDisposition = new  
     ContentDispositionHeaderValue("attachment")  
       {  
        FileName = Path.GetFileName(FileName)  
       };  
 content.Add(fileContent);  

var requestUri = "http://localhost:8170/Home/UploadFile/";  
    try  
    {  
        var result = client.PostAsync(requestUri, content).Result;  
        rslt = true;  
    }  
    catch (Exception ex)  
    {  
        // log error  
        rslt = false;  
    }  
}  
}  
return rslt;  
}  


So, that's the supporting code out of the way. One of the critical things to be aware of next is the file naming convention that is being used. It consists of the original file-name, plus a code-parsable tail "_part." that will be used server-side to merge the different file chunks back into a single contiguous file again. This is simply the convention I put together - you can change it to your own requirements, just be sure you are consistent with it.

The convention for this example is,
Name = original name + ".part_N.X" (N = file part number, X = total files).

Here is an example of a picture file split into three parts.
MyPictureFile.jpg.part_1.3
MyPictureFile.jpg.part_2.3
MyPictureFile.jpg.part_3.3

It doesn't matter what order the file chunks are sent to the Server. The important thing is that some convention, like the above is used, so that the Server knows (a) what file part it is dealing with and (b) when all parts have been received and can be merged back into one large original file again.

Next, here is the meat of the C# code that scans the file, creating multiple chunk files ready to transfer.
public bool SplitFile()  
{  
bool rslt = false;  
string BaseFileName = Path.GetFileName(FileName);  
// set the size of file chunk we are going to split into  
int BufferChunkSize = MaxFileSizeMB * (1024 * 1024);  
// set a buffer size and an array to store the buffer data as we read it  
const int READBUFFER_SIZE = 1024;  
byte[] FSBuffer = new byte[READBUFFER_SIZE];  
// open the file to read it into chunks  
using (FileStream FS = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.Read))  
{  
// calculate the number of files that will be created  
int TotalFileParts = 0;  
if (FS.Length < BufferChunkSize)  
{  
    TotalFileParts = 1;  
}  
else  
{  
    float PreciseFileParts = ((float)FS.Length / (float)BufferChunkSize);  
    TotalFileParts = (int)Math.Ceiling(PreciseFileParts);  
}  

int FilePartCount = 0;  
// scan through the file, and each time we get enough data to fill a chunk, write out that file  
while (FS.Position < FS.Length)  
{  
    string FilePartName = String.Format("{0}.part_{1}.{2}",  
    BaseFileName, (FilePartCount + 1).ToString(), TotalFileParts.ToString());  
    FilePartName = Path.Combine(TempFolder, FilePartName);  
    FileParts.Add(FilePartName);  
    using (FileStream FilePart = new FileStream(FilePartName, FileMode.Create))  
    {  
        int bytesRemaining = BufferChunkSize;  
        int bytesRead = 0;  
        while (bytesRemaining > 0 && (bytesRead = FS.Read(FSBuffer, 0,  
         Math.Min(bytesRemaining, READBUFFER_SIZE))) > 0)  
        {  
            FilePart.Write(FSBuffer, 0, bytesRead);  
            bytesRemaining -= bytesRead;  
        }  
    }  
  // file written, loop for next chunk  
  FilePartCount++;  
}  

}  
return rslt;  
}  


That's it for the C# client-side - we will see the result and how to handle things server-side later in the article. Next, let's look at how to do the same thing in Javascript, from a web-browser.
JavaScript File Split

NB - The JavaScript code, and the C# Merge code are contained in the attached demo file "MVCServer"

In our browser, we have an input control of type "file", and a button to call a method that initiates the file-split and data transfer.
<input type="file" id="uploadFile" name="file" />  <a class="btn btn-primary" href="#" id="btnUpload">Upload file</a>  

On document ready, we bind to the click event of the button to call the main method.
$(document).ready(function () {  
$('#btnUpload').click(function () {  
UploadFile($('#uploadFile')[0].files);  
}  
)  
});  


Our UploadFile method does the work of splitting the file into chunks, and as in our C# example, passing the chunks off to another method for transfer. The main difference here is that in C#, we created individual files, in our JavaScript example, we are taking the chunks from an array instead.  
function UploadFile(TargetFile)  
{  
// create array to store the buffer chunks  
var FileChunk = [];  
// the file object itself that we will work with  
var file = TargetFile[0];  
// set up other initial vars  
var MaxFileSizeMB = 1;  
var BufferChunkSize = MaxFileSizeMB * (1024 * 1024);  
var ReadBuffer_Size = 1024;  
var FileStreamPos = 0;  
// set the initial chunk length  
var EndPos = BufferChunkSize;  
var Size = file.size;  

// add to the FileChunk array until we get to the end of the file  
while (FileStreamPos < Size)  
{  
// "slice" the file from the starting position/offset, to  the required length  
FileChunk.push(file.slice(FileStreamPos, EndPos));  
FileStreamPos = EndPos; // jump by the amount read  
EndPos = FileStreamPos + BufferChunkSize; // set next chunk length  
}  
// get total number of "files" we will be sending  
var TotalParts = FileChunk.length;  
var PartCount = 0;  
// loop through, pulling the first item from the array each time and sending it  
while (chunk = FileChunk.shift())  
{  
PartCount++;  
// file name convention  
var FilePartName = file.name + ".part_" + PartCount + "." + TotalParts;  
// send the file  
UploadFileChunk(chunk, FilePartName);  
}  
}  


The UploadFileChunk takes the part of the file handed by the previous method, and posts it to the Server in a similar manner to the C# example.
function UploadFileChunk(Chunk, FileName)  
{  
var FD = new FormData();  
FD.append('file', Chunk, FileName);  
$.ajax({  
type: "POST",  
url: 'http://localhost:8170/Home/UploadFile/',  
contentType: false,  
processData: false,  
data: FD  
});  
}  


File merge
NB - The JavaScript code, and the C# Merge code are contained in the attached demo file "MVCServer"

Over on the Server, be that MVC or Web-API, we receive the individual file chunks and need to merge them back together again into the original file.

The first thing we do is put a standard POST handler in place to receive the file chunks being posted up to the Server. This code takes the input stream, and saves it to a temp folder using the file-name created by the client (C# or JavaScript). Once the file is saved, the code then calls the "MergeFile" method which checks if it has enough file chunks available yet to merge the file together. Note that this is simply the method I have used for this article. You may decide to handle the merge trigger differently, for example, running a job on a timer every few minutes, passing off to another process, etc. It should be changed depending on your own required implementation.

[HttpPost]  
public HttpResponseMessage UploadFile()  
{  
foreach (string file in Request.Files)  
{  
var FileDataContent = Request.Files[file];  
if (FileDataContent != null && FileDataContent.ContentLength > 0)  
{  
    // take the input stream, and save it to a temp folder using  
    // the original file.part name posted  
    var stream = FileDataContent.InputStream;  
    var fileName = Path.GetFileName(FileDataContent.FileName);  
    var UploadPath = Server.MapPath("~/App_Data/uploads");  
    Directory.CreateDirectory(UploadPath);  
    string path = Path.Combine(UploadPath, fileName);  
    try  
    {  
        if (System.IO.File.Exists(path))  
            System.IO.File.Delete(path);  
        using (var fileStream = System.IO.File.Create(path))  
        {  
            stream.CopyTo(fileStream);  
        }  
        // Once the file part is saved, see if we have enough to merge it  
        Shared.Utils UT = new Shared.Utils();  
        UT.MergeFile(path);  
    }  
    catch (IOException ex)  
    {  
       // handle  
    }  
}  
}  
return new HttpResponseMessage()  
{  
StatusCode = System.Net.HttpStatusCode.OK,  
Content = new StringContent("File uploaded.")  
};  
}  


Each time we call the MergeFile method, it first checks to see if we have all of the file chunk parts required to merge the original file back together again. It determines this by parsing the file-names. If all files are present, the method sorts them into the correct order, and then appends one to another until the original file that was split, is back together again.
/// <summary>  
/// original name + ".part_N.X" (N = file part number, X = total files)  
/// Objective = enumerate files in folder, look for all matching parts of  
/// split file. If found, merge and return true.  
/// </summary>  
/// <param name="FileName"></param>  
/// <returns></returns>  
public bool MergeFile(string FileName)  
{  
bool rslt = false;  
// parse out the different tokens from the filename according to the convention  
string partToken = ".part_";  
string baseFileName = FileName.Substring(0, FileName.IndexOf(partToken));  
string trailingTokens = FileName.Substring(FileName.IndexOf(partToken) + partToken.Length);  
int FileIndex = 0;  
int FileCount = 0;  
int.TryParse(trailingTokens.Substring(0, trailingTokens.IndexOf(".")), out FileIndex);  
int.TryParse(trailingTokens.Substring(trailingTokens.IndexOf(".") + 1), out FileCount);  
// get a list of all file parts in the temp folder  
string Searchpattern = Path.GetFileName(baseFileName) + partToken + "*";  
string[] FilesList = Directory.GetFiles(Path.GetDirectoryName(FileName), Searchpattern);  
//  merge .. improvement would be to confirm individual parts are there / correctly in  
// sequence, a security check would also be important  
// only proceed if we have received all the file chunks  
if (FilesList.Count() == FileCount)  
{  
// use a singleton to stop overlapping processes  
if (!MergeFileManager.Instance.InUse(baseFileName))  
{  
    MergeFileManager.Instance.AddFile(baseFileName);  
    if (File.Exists(baseFileName))  
        File.Delete(baseFileName);  
    // add each file located to a list so we can get them into  
    // the correct order for rebuilding the file  
    List<SortedFile> MergeList = new List<SortedFile>();  
    foreach (string File in FilesList)  
    {  
        SortedFile sFile = new SortedFile();  
        sFile.FileName = File;  
        baseFileName = File.Substring(0, File.IndexOf(partToken));  
        trailingTokens = File.Substring(File.IndexOf(partToken) + partToken.Length);  
        int.TryParse(trailingTokens.  
           Substring(0, trailingTokens.IndexOf(".")), out FileIndex);  
        sFile.FileOrder = FileIndex;  
        MergeList.Add(sFile);  
    }  
    // sort by the file-part number to ensure we merge back in the correct order  
    var MergeOrder = MergeList.OrderBy(s => s.FileOrder).ToList();  
    using (FileStream FS = new FileStream(baseFileName, FileMode.Create))  
    {  
        // merge each file chunk back into one contiguous file stream  
        foreach (var chunk in MergeOrder)  
        {  
            try  
            {  
                using (FileStream fileChunk =  
                   new FileStream(chunk.FileName, FileMode.Open))  
                {  
                    fileChunk.CopyTo(FS);  
                }  
            }  
            catch (IOException ex)  
            {  
                // handle  
            }  
        }  
    }  
    rslt = true;  
    // unlock the file from singleton  
    MergeFileManager.Instance.RemoveFile(baseFileName);  
}  
}  
return rslt;  
}  


Using the file split on the client-side, and file-merge on the server-side, we now have a very workable solution for uploading large files in a more secure manner than simply sending up in one large block of data.



About HostForLIFE

HostForLIFE is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2019 Hosting, ASP.NET 5 Hosting, ASP.NET MVC 6 Hosting and SQL 2019 Hosting.


Tag cloud

Sign in