EDIT
AUTHOR COMMENTS: I just want the service layer (Web API) to be separate from the web site since I will have 3 applications using the same service layer: Blog, CMS and Web Site. I appreciate the complete class if possible. Thank You
Yes, it is a good idea to make it separate and don't relay on adding as a reference. It is because someday you may want to deploy on a separate server. Or having a different deployment process, implementing Continuous Integration Development Process.
So from all our discussion it is clear that you are going to implement as:
How you are going to call WebApi from your other .Net Applications?
The simple thing you are going to use is HttpClient class added in .Net Framework 4.5 (?) I think.
using (var client = new HttpClient())
{
// New code:
client.BaseAddress = new Uri("http://localhost:9000/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
- How am I going to send an image along with data to an WebApi?
You can use this code from my project as a reference:
[HttpPost]
public async Task<IHttpActionResult> UploadFileAsync()
{
IHttpActionResult actionResult = null;
if (Request.Content.IsMimeMultipartContent())
{
// Read the file and form data.
MultipartFormDataMemoryStreamProvider provider = new MultipartFormDataMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
// get form data from like provider.FormData["description"];
if (!provider.FileStreams.Any())
{
actionResult = BadRequest(ValidationMessages.FileNotFound);
}
else
{
var ownerID = 0;
var ownerType = provider.FormData.Get("ownerType");
int.TryParse(provider.FormData.Get("ownerID"), out ownerID);
List<Document> documents = new List<Document>();
foreach (KeyValuePair<NameValueCollection, Stream> file in provider.FileStreams)
{
NameValueCollection fileHeader = file.Key;
string fileName = fileHeader.Get("FileName");
string contentType = fileHeader.Get("ContentType");
Stream stream = file.Value;
using (var reader = new BinaryReader(stream))
{
var fileBytes = reader.ReadBytes((int)stream.Length);
var document = new Document()
{
FileName = fileName,
Extension = Path.GetExtension(fileName),
Binary = fileBytes,
ContentType = contentType,
Size = fileBytes.LongLength
};
if (ownerID > 0)
{
document.RequestID = ownerID;
}
documents.Add(document);
}
}
if (documents.Count() > 0)
{
string exceptionMessages = string.Empty;
if (this.DomainService.InsertRange(documents, out exceptionMessages))
{
actionResult = Created(string.Empty, documents);
}
else
{
actionResult = BadRequest(exceptionMessages);
}
}
else
{
actionResult = BadRequest(ValidationMessages.FileNotFound);
}
}
}
else
{
// The response to upload did not came with Multiple content;
actionResult = BadRequest(ValidationMessages.MimeNotFound);
}
return actionResult;
}
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web;
namespace Webapi.Helper
{
public class MultipartFormDataMemoryStreamProvider : MultipartMemoryStreamProvider
{
private readonly Collection<bool> _isFormData = new Collection<bool>();
private readonly NameValueCollection _formData = new NameValueCollection(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<NameValueCollection, Stream> _fileStreams = new Dictionary<NameValueCollection, Stream>();
public NameValueCollection FormData
{
get { return _formData; }
}
public Dictionary<NameValueCollection, Stream> FileStreams
{
get { return _fileStreams; }
}
public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
{
if (parent == null)
{
throw new ArgumentNullException("parent");
}
if (headers == null)
{
throw new ArgumentNullException("headers");
}
var contentDisposition = headers.ContentDisposition;
if (contentDisposition == null)
{
throw new InvalidOperationException("Did not find required 'Content-Disposition' header field in MIME multipart body part.");
}
_isFormData.Add(String.IsNullOrEmpty(contentDisposition.FileName));
return base.GetStream(parent, headers);
}
public override async Task ExecutePostProcessingAsync()
{
for (var index = 0; index < Contents.Count; index++)
{
HttpContent formContent = Contents[index];
if (_isFormData[index])
{
// Field
string formFieldName = UnquoteToken(formContent.Headers.ContentDisposition.Name) ?? string.Empty;
string formFieldValue = await formContent.ReadAsStringAsync();
FormData.Add(formFieldName, formFieldValue);
}
else
{
Stream stream = await formContent.ReadAsStreamAsync(); // File
/// we are not going to accept any stream that has no value!!
if (stream.Length > 0)
{
string fileName = UnquoteToken(formContent.Headers.ContentDisposition.FileName);
NameValueCollection fileHeader = new NameValueCollection();
fileHeader.Add("FileName", fileName);
fileHeader.Add("ContentType", UnquoteToken(formContent.Headers.ContentType.MediaType));
FileStreams.Add(fileHeader, stream);
}
}
}
}
private static string UnquoteToken(string token)
{
if (string.IsNullOrWhiteSpace(token))
{
return token;
}
if (token.StartsWith("\"", StringComparison.Ordinal) && token.EndsWith("\"", StringComparison.Ordinal) && token.Length > 1)
{
return token.Substring(1, token.Length - 2);
}
return token;
}
}
}
How I am going to secure so that only my applications can connect with WebApi?
Well the short answer is that you can use Private key shared between applications by following this architecture.
There are many code available on the net that can help you with this.