There was an email earlier this year about a change in declarations from my employer. You can’t just drop receipt on someone’s desk anymore, but since we are in a digital era, we should make a picture of it and send it by mail. That sounds fair. But that would require me to remember the constraints, like letting know for which client it is and to which address I should send it to. So I decided that it needed automation.

Because some coworkers have iPhones and some have Android, I decided to go for this approach:

architecture

Xamarin Forms (Android, iOs) post a picture of a receipt to Azure Functions in the Azure cloud which sends it to Sendgrid. (Because Azure Functions cannot send mail)

Here are the steps I took to make a simple camera app:

1. File, new project, new Xamarin Forms project (no web api)

2. Add new project to solution (Azure Functions)

3. Add the nuget package ‘Xam.Plugin.Media’ to the shared/main xamarin project

4. Add UI code:



        

5. Add code to cs (code behind file)

I had three class variables (type string) filePath, filename, url (url to your azure function) I forgot that the emulator is a vm so you can’t use the localhost if you are testing the Azure Function but you should use your LAN ip.


private async void takePhoto_Clicked(object sender, EventArgs e)
{
	if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
	{
		await DisplayAlert("No Camera", ":( No camera avaialble.", "OK");
		return;
	}
	filename = DateTime.Now.ToString("yyyyMMdd-") + Guid.NewGuid() + ".jpg";

	var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions
	{
		PhotoSize = PhotoSize.Medium,
		Directory = "Sample",
		Name = filename
	});

	if (file == null)
		return;

	filePath = file.Path;

	image.Source = ImageSource.FromStream(() =>
	{
		var stream = file.GetStream();
		file.Dispose();
		return stream;
	});
	sendPhoto.IsEnabled = true;
}

private async void sendPhoto_Clicked(object sender, EventArgs e)
{
	HttpContent fileStreamContent = new StreamContent(File.OpenRead(filePath));
	fileStreamContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data") { Name = "file", FileName = filename };
	fileStreamContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");

	using (var client = new HttpClient())
	using (var formData = new MultipartFormDataContent())
	{
		formData.Add(fileStreamContent);
		var response = await client.PostAsync(url, formData);
	}
}

6. add `await CrossMedia.Current.Initialize();` in the android project in the mainactivity.cs just below the OnCreate call

7. add this code to the azure function:


string imageBase64;

using (var ms = new MemoryStream())
{
	file.CopyTo(ms);
	var fileBytes = ms.ToArray();
	imageBase64 = Convert.ToBase64String(fileBytes);
}

string sendgridApiKey = "api-key-here";

var client = new SendGridClient(sendgridApiKey);
var from = new EmailAddress("mymailaddress@partech.nl", "JP Hellemons");
var subject = "Declaraton from app";
var to = new EmailAddress("mymailaddress@partech.nl", "JP");

var msg = MailHelper.CreateSingleEmail(from, to, subject, "plain msg", "html version");
msg.AddAttachment(file.FileName, imageBase64, "image/jpeg", "attachment");
var response = await client.SendEmailAsync(msg);

return new OkObjectResult("");


8. of course make a free account at sendgrid and just follow the tutorial/docs for adding the nuget package to the Azure Function.


Next post will contain a link to the Azure Active Directory for authenticating so that not everybody will send in receipts on my behalf.

Good luck!

Post on LinkedIn