Saturday, 21 November 2020

Upload excel file as multipart

 Upload excel file as multipart


Client:

===========================================================


using System;

using System.Collections.Generic;

using System.Linq;

using System.Net.Http;

using System.Text;

using System.Threading.Tasks;


namespace QTC.OMS_Intake.UtilityLayer.HttpClientBase

{

    public  class UploadFileClientLocator: IHttpClientLocator

    {

        private static volatile object SyncRoot = new object();

        private static volatile IHttpClient _internalClient;


        private void InitializeClient(HttpClientHandler handler)

        {

            var client = new BasicHttpClient(handler)

            {

                Timeout = TimeSpan.FromSeconds(60)

            };


            lock (SyncRoot)

            {

                _internalClient = client;


            }

        }

        public IHttpClient Locate(HttpClientHandler handler)

        {

            if (_internalClient == null)

            {

                InitializeClient(handler);

            }


            return _internalClient;

        }

    }

}




--------------------------

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace QTC.OMS_Intake.UtilityLayer.HttpClientBase
{
    public  class BasicHttpClient : IHttpClient
    {
        private readonly HttpClient _internalClient;
        private readonly HashSet<Uri> _endpointCalled;
        public BasicHttpClient()
        {
            _internalClient = new HttpClient();
            _endpointCalled = new HashSet<Uri>();
        }

        public BasicHttpClient(HttpClientHandler handler)
        {
            _internalClient = new HttpClient(handler);
            _endpointCalled = new HashSet<Uri>();
        }

        public HttpRequestHeaders RequestHeaders { get => _internalClient.DefaultRequestHeaders; }
        public TimeSpan Timeout { set => _internalClient.Timeout = value; }
        public TimeSpan TimeOut { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
        public Uri BaseAddress { get => _internalClient.BaseAddress; set => _internalClient.BaseAddress = value; }
        public HttpRequestHeader RequestHeader { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }

        public void Dispose()
        {
            lock (_endpointCalled)
            {
                _endpointCalled.Clear();
            }
            _internalClient.Dispose();
        }

        public async Task<HttpResponseMessage> GetAsync(Uri requestUri)
        {
            var httprequestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri);
            var stopwatch = Stopwatch.StartNew();
            var getAsync = await _internalClient.SendAsync(httprequestMessage)
                .ConfigureAwait(false);
            stopwatch.Stop();
            var time = stopwatch.ElapsedMilliseconds;
            return getAsync;
        }

        public async Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content)
        {
            var payload = content.ReadAsStringAsync().Result;
            var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri)
            {
                Content = content
            };
            var stopwatch = Stopwatch.StartNew();
            try
            {
                var postAsync =await _internalClient.SendAsync(httpRequestMessage)
                    .ConfigureAwait(false);
                stopwatch.Stop();
                return postAsync;
            }
            catch (Exception)
            {
                stopwatch.Stop();
                throw;
            }
        }

        public async Task<HttpResponseMessage> PuttAsync(Uri requestUri, HttpContent content)
        {
            var httpRequestMessage = new HttpRequestMessage(HttpMethod.Put, requestUri)
            {
                Content = content
            };
            var stopwatch = Stopwatch.StartNew();
            try
            {
                var putAsync = await _internalClient.SendAsync(httpRequestMessage)
                    .ConfigureAwait(false);
                stopwatch.Stop();
                return putAsync;
            }
            catch (Exception)
            {
                stopwatch.Stop();
                throw;
            }
        }
    }
}

-------------

using System;

using System.Collections.Generic;

using System.Configuration;

using System.IO;

using System.Linq;

using System.Net.Http;

using System.Net.Http.Headers;

using System.Text;

using System.Threading.Tasks;

using System.Web;

using Newtonsoft.Json;

using QTC.OMS_Intake.BusinessLayer.ManagerClasses;

using QTC.OMS_Intake.UtilityLayer;

using QTC.OMS_Intake.UtilityLayer.HttpClientBase;


namespace QTC.OMS_Intake.ViewModelLayer

{

    public class RequestMetaDataViewModel : AppViewModelBase

    {

        private readonly IHttpClientLocator _httpClientLocator;

        private readonly UploadRequestManager _uploadRequestManager;


        public RequestMetaDataViewModel()

        {

             _httpClientLocator = new UploadFileClientLocator();

            _uploadRequestManager = new UploadRequestManager();

        }


        public HttpPostedFileBase MetaData { get; set; }

        public bool IsExist { get; set; }

        public bool IsSuccess { get; set; }

        public bool UploadFileRequest(UploadFileRequestModel request)

        {

            var serialzedRequest = JsonConvert.SerializeObject(request);

            var content = new MultipartFormDataContent();


            content.Add(new StreamContent(new MemoryStream(request.FileData)), request.FileName, request.FileName,

                new

                {

                    user = request.UserName,

                    appid = request.AppId

                }

            );

            var baseApiUrl = ConfigurationManager.AppSettings["UploadFileAPI"];

            var uploadUrl = $"{baseApiUrl}/api/Upload/InclinicUpload";

            var handler = new HttpClientHandler();

            handler.Credentials = System.Net.CredentialCache.DefaultCredentials;


            var client = _httpClientLocator.Locate(handler);

            

            var result = client.PostAsync(new Uri(uploadUrl), content).Result;

            var response = result.Content.ReadAsStringAsync().Result;

            var responseModel = JsonConvert.DeserializeObject<UploadFileResponseModel>(response);

            //result.EnsureSuccessStatusCode();

            

            //for future

            //var response = result.Content.ReadAsStringAsync().Result;

            //var responseModel = JsonConvert.DeserializeObject<UploadFileResponseModel>(response);

            return IsSuccess;

        }


        public bool CheckFileExist(string fileName)

        {

            var uploadHistory = _uploadRequestManager.GetUploadHistory();

            var isExist = uploadHistory.FirstOrDefault(uh => uh.FileName == fileName);

            if (isExist == null)

                IsExist = false;

            else

                IsExist = true;

            return IsExist;

        }

    }

}



Server

==========================================================

using Newtonsoft.Json;

using Qtc.RhrpApi.BusinessLayer.DTO.OMSUpload;

using Qtc.RhrpApi.BusinessLayer.Extensions;

using Qtc.RhrpApi.BusinessLayer.ManagerClasses;

using QTC.Web.WebApi;

using System;

using System.Collections.Generic;

using System.Data.SqlClient;

using System.Linq;

using System.Net;

using System.Net.Http;

using System.Text;

using System.Web;

using System.Web.Http;

using static Qtc.RhrpApi.BusinessLayer.ManagerClasses.LogExceptionManager;


namespace Qtc.RhrpApi.WebApi.Controllers.OMSUpload

{

    public class UploadController : QTCWebApiControllerBase

    {


        [HttpPost]

        public HttpResponseMessage InclinicUpload()

        {

            UploadResponse uploadResp = new UploadResponse();

            HttpResponseMessage response = new HttpResponseMessage();



            if (!Request.Content.IsMimeMultipartContent())

                throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);


            var provider = new MultipartMemoryStreamProvider();

            Request.Content.ReadAsMultipartAsync(provider);


            // Loop through all uploaded files

            foreach (var file in provider.Contents)

            {

                var fn = file.Headers.ContentDisposition.FileName;

                var user = file.Headers.ContentDisposition.Parameters.Where(u => u.Name == "user").Select(u => u.Value).FirstOrDefault();

                var app = file.Headers.ContentDisposition.Parameters.Where(u => u.Name == "appid").Select(u => u.Value).FirstOrDefault();

                FileResponse fileResponse = new FileResponse();


                try

                {

                    if (fn == null || user == null || app == null)

                    {

                        uploadResp.FileResponses.Add(new FileResponse { FileError = "filename, user and appid are required in the request header!" });

                        break;

                    }


                    var filename = fn.Trim('\"');

                    string userName = user.Trim('\"');

                    string AppId = app.Trim('\"');

                    fileResponse.FileName = filename;


                    var buffer = file.ReadAsByteArrayAsync().Result;


                    // Parse uploaded XLSM file

                    XlsmFileProcessor xlsmFileProcessor = new XlsmFileProcessor(buffer, userName, AppId);

                    bool bSuccess = xlsmFileProcessor.ProcessInclinicData(filename, out fileResponse);

                    if (!bSuccess)

                    {

                        uploadResp.FileResponses.Add(fileResponse);

                    }

                }

                catch (SqlException sqlException)

                {

                    fileResponse.FileError = sqlException.Message + System.Environment.NewLine + sqlException.StackTrace;

                    LogExceptionManager.Instance.Publish(Guid.Empty, Guid.Empty, "UploadController.InclinicUpload() HttpPost", SEVERITY.Fatal, "", sqlException.GetAllMessages(), "", user);

                    uploadResp.FileResponses.Add(fileResponse);

                }

                catch (Exception ex)

                {

                    fileResponse.FileError = ex.Message + System.Environment.NewLine + ex.StackTrace;

                    // re-throw cause the error page to display

                    LogExceptionManager.Instance.Publish(Guid.Empty, Guid.Empty, "UploadController.InclinicUpload() HttpPost", SEVERITY.Fatal, "", ex.GetAllMessages(), "", user);

                    uploadResp.FileResponses.Add(fileResponse);

                }

            }

            if (uploadResp.FileResponses.Count > 0)

            {

                HttpError err = new HttpError(JsonConvert.SerializeObject(uploadResp));

                response = Request.CreateResponse(HttpStatusCode.BadRequest, err);

            }

            else

            {

                response = Request.CreateResponse(HttpStatusCode.OK);

            }

            return response;

        }

    }

}

------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Qtc.RhrpApi.BusinessLayer.DTO.OMSUpload
{
    public class UploadResponse
    {
        public List<FileResponse> FileResponses { get; set; }

        public UploadResponse()
        {
            FileResponses = new List<FileResponse>();
        }        
    }

    public class FileResponse
    {

        public string FileName { get; set; }
        public List<Dictionary<string, string>> LineError;
        public string FileError { get; set; }

        public FileResponse()
        {
            LineError = new List<Dictionary<string, string>>();
        }
    }
}


--------------------------------------------------------------------

using Newtonsoft.Json;
using NPOI.SS.UserModel;
using Qtc.RhrpApi.BusinessLayer.DTO.OMSUpload;
using Qtc.RhrpApi.BusinessLayer.EntityClasses;
using Qtc.RhrpApi.BusinessLayer.ManagerClasses.OMSUpload;
using Qtc.RhrpApi.BusinessLayer.Validation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;

namespace Qtc.RhrpApi.WebApi.Controllers.OMSUpload
{
    public class XlsmFileProcessor
    {
        const string nsXsd = "http://schemas.datacontract.org/2004/07/Qtc.RhrpApi.BusinessLayer.EntityClasses";
        public object WorkbookFactory { get; private set; }
        public byte[] FileContent { get; set; }
        public Guid ApplicationId { get; set; }
        public string User { get; set; }

        public XlsmFileProcessor(byte[] fileContent, string userName, string appID) 
        {
            FileContent = fileContent;
            User = userName;
            ApplicationId = string.IsNullOrEmpty(appID) ? Guid.NewGuid() : Guid.Parse(appID);
        }

        /// <summary>
        /// Parse service member(s) on "In-Clinic Request" spreadsheet
        /// Save sm data to the database if successful
        /// Return error if failed
        /// </summary>
        /// <param name="errMessage">List of errors</param>
        /// <returns>true: success; false: failed</returns>
        public bool ProcessInclinicData(string fileName, out FileResponse fileResponse) 
        {
            IWorkbook workbook;
            FileResponse rtnResp = new FileResponse();
            rtnResp.FileName = fileName; 
            bool result = true;

            try
            {               
                using (Stream sr = new MemoryStream(FileContent))
                {
                    workbook = NPOI.SS.UserModel.WorkbookFactory.Create(sr);
                }

                var importer = new Npoi.Mapper.Mapper(workbook);

                var excelInClinicList = importer.Take<InClinicData>("In-Clinic Request").ToList();

                InClinicList inClinicList = new InClinicList();
                inClinicList.ServiceMembers = excelInClinicList.Select(x => x.Value).ToList();

                if (inClinicList.ServiceMembers.Count == 0)
                {
                    rtnResp.FileError = "No service member found!";
                    fileResponse = rtnResp;
                    UploadManager.Instance.InsertUploadHistory(fileName, "Fail", JsonConvert.SerializeObject(rtnResp), User);
                    return false;
                }

                List<Dictionary<string, string>> lstErr = new List<Dictionary<string, string>>();
                int iLineNo = 0;
                // Validate every SM data
                foreach (var sm in inClinicList.ServiceMembers)
                {
                    iLineNo++;
                    Dictionary<string, string> dictError = new Dictionary<string, string>();
                    bool valid = ValidateData<InClinicData>(sm, out dictError);
                    if (!valid)
                    {
                        dictError.Add("LineNo", iLineNo.ToString());
                        rtnResp.LineError.Add(dictError);
                        result = false;
                    }
                }               

                if (rtnResp.LineError.Count == 0)
                {
                    UploadManager.Instance.CreateRequest(inClinicList.ServiceMembers, ApplicationId, User, fileName);
                    result = true;
                }
                else
                {
                    UploadManager.Instance.InsertUploadHistory(fileName, "Fail", JsonConvert.SerializeObject(rtnResp), User);
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex);
                rtnResp.FileError = ex.Message + System.Environment.NewLine + ex.StackTrace;
                throw ex;
            }
            fileResponse = rtnResp;
            return result; 
        }

        /// <summary>
        /// Validate all properties in dataObject
        /// </summary>
        /// <typeparam name="T">Type for dataObject</typeparam>
        /// <param name="dataObject">class object to validate</param>
        /// <param name="dictError">Error list</param>
        /// <returns>true: valid; false: invalid</returns>
        private bool ValidateData<T>(object dataObject, out Dictionary<string, string> dictError)
        {
            Dictionary<string, string> errList = new Dictionary<string, string>();
         
            ValidationAttributeValidator<T> validator = new ValidationAttributeValidator<T>();
            PropertyInfo[] properties = typeof(T).GetProperties();

            foreach (PropertyInfo property in properties)
            {
                System.Diagnostics.Debug.WriteLine("Name: " + property.Name + ", Value: " + property.GetValue(dataObject, null));

                string errMsg = string.Empty;
                if (!validator.ValidateValidationAttribute(property.Name, property.GetValue(dataObject, null), out errMsg))
                {
                    errList.Add(property.Name, errMsg);
                }
            }
            dictError = errList;
            return (dictError.Count == 0);
        }

    }
}


-----------------------------------------------

using Qtc.RhrpApi.BusinessLayer.Validation;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace Qtc.RhrpApi.BusinessLayer.EntityClasses
{
    public class InClinicList
    {
        [XmlElementAttribute("ServiceMembers")]
        public List<InClinicData> ServiceMembers { get; set; }
    }

    public class InClinicData : ServiceMember
    {
        [SingleChildServiceAttribute(ErrorMessage = "Single child rule violated")]
        public string PhaseIds { get; set; }
    }

}

----------------------------

using Qtc.RhrpApi.BusinessLayer.Validation;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;

namespace Qtc.RhrpApi.BusinessLayer.EntityClasses
{
    [Table("UploadInClinicData")]
    public abstract class ServiceMember
    {
        public ServiceMember()
        {
            TempId = Guid.NewGuid();
        }
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public Guid TempId { get; set; }
        public Guid UploadId { get; set; }

        [Required(ErrorMessage = "You must Request Type")]
        public string RequestType { get; set; }

        //[DataType(DataType.Date)]
        [DateRange("1/1/1753", "12/31/9999", ErrorMessage = "Invalid Request Date")]
        [Required(ErrorMessage = "You must provide Request Date")]
        public DateTime RequestDate { get; set; }

        [Required(ErrorMessage = "You must provide SSN")]
        [RegularExpression("^[0-9]{9}$", ErrorMessage = "Invalid SSN")]
        public string SSN { get; set; }

        [Required(ErrorMessage = "You must provide DOD ID")]
        [RegularExpression("^[0-9]*$", ErrorMessage = "Invalid DOD ID")]
        public string DODId { get; set; }

        [RegularExpression("^([a-zA-Z0-9]+)$", ErrorMessage = "Invalid UIC")]
        public string UIC { get; set; }

        [DataType(DataType.Date)]
        [DateRange("1/1/1753", "12/31/9999", ErrorMessage = "Invalid DOB")]
        [AgeMinimunLimit(17, ErrorMessage = "Age limit must be between 17-70 years")]
        [AgeMaximumLimit(70, ErrorMessage = "Age limit must be between 17-70 years")]
        public Nullable<DateTime> DOB { get; set; }
        public string Gender { get; set; }
        public string ServiceComponent { get; set; }

        [Required(ErrorMessage = "You must provide a First Name")]
        [RegularExpression("^([a-zA-Z- ~.'’ñ]+)$", ErrorMessage = "Invalid First Name")]
        public string FirstName { get; set; }

        [Required(ErrorMessage = "You must provide a Last Name")]
        [RegularExpression("^([a-zA-Z- ~.'’ñ]+)$", ErrorMessage = "Invalid Last Name")]
        public string LastName { get; set; }
        public string MiddleInitial { get; set; }

        //[RegularExpression("^[^@]+@[a-zA-Z0-9._-]+\\.+[a-z._-]+$", ErrorMessage = "Invalid Email Address")]
        [RegularExpression("^[_a-zA-Z0-9-]+(\\.[_a-zA-Z0-9-]+)*(\\+[a-zA-Z0-9-]+)?@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*$", ErrorMessage = "Invalid Email Address")]
        public string Email { get; set; }

        [RegularExpression(@"^(\([2-9]\d{2}\)|[2-9]\d{2})(?:\-?|\ ?|\.?)([0-9]\d{2})(?:\-?|\ ?|\.?)(\d{4})$", ErrorMessage = "Invalid Cell Phone.")]
        public string CellPhone { get; set; }

        [RegularExpression(@"^(\([2-9]\d{2}\)|[2-9]\d{2})(?:\-?|\ ?|\.?)([0-9]\d{2})(?:\-?|\ ?|\.?)(\d{4})$", ErrorMessage = "Invalid Daytime Phone.")]
        public string DayPhone { get; set; }

        [RegularExpression("^([a-zA-Z0-9- #./']+)$", ErrorMessage = "Invalid Address 1")]
        public string HomeAddressLine1 { get; set; }

        [RegularExpression("^([a-zA-Z0-9- #./']+)$", ErrorMessage = "Invalid Address 2")]
        public string HomeAddressLine2 { get; set; }

        [RegularExpression("^[a-zA-Z]+(?:[\\s-][a-zA-Z]+)*$", ErrorMessage = "Invalid city")]
        public string City { get; set; }

        public string State { get; set; }

        [RegularExpression("^[0-9]{5}(?:-[0-9]{4})?$", ErrorMessage = "Invalid zip code")]
        public string ZipCode { get; set; }

        public string CreatedUser { get; set; }
        public DateTime CreatedDate { get; set; }
    }
}

----------------------

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Qtc.RhrpApi.BusinessLayer.Validation
{
    //T = class type containing the properties to be validated
    public class ValidationAttributeValidator<T>
    {
        public ValidationAttributeValidator() { }

        // Validate one property against all validation attributes
        public bool ValidateValidationAttribute(string property, object value, out string error)
        {
            var propertyInfo = typeof(T).GetProperty(property);
            var validationAttributes = propertyInfo.GetCustomAttributes(true);

            if (validationAttributes == null)
            {
                error = "No customer attribute found!";
                return true;
            }
            
            // Loop through all validation attributes
            foreach (object attribute in validationAttributes)
            {
                System.Diagnostics.Debug.WriteLine(" - Validation Attribute: " + (attribute.GetType()).Name);
                if ((attribute.GetType()).Name == "KeyAttribute" || (attribute.GetType()).Name == "DatabaseGeneratedAttribute"
                    || (attribute.GetType()).Name == "DisplayFormatAttribute"
                    || (attribute.GetType()).Name == "DisplayAttribute")
                    continue;

                if (!((ValidationAttribute)attribute).IsValid(value))
                {
                    error = ((ValidationAttribute)attribute).ErrorMessage + (value == null ? "" : "(" + value.ToString() + ")");
                    return false;
                }
            }
            error = string.Empty;
            return true; 
        }

    }


}

------------------------------------------------------------


No comments:

Post a Comment