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;
}
}
}
------------------------------------------------------------