Xamarin How to send a Post with my entrys - api

I need to fill a form with inputs in Xamarin, and send them to my API page.
I already tried sending the data in "Postman" and it saved it correctly, but I would like to know how to send it from Xamarin.
Attention, I can read the data correctly from the application.
public class FuelPurchase
{
public int id { get; set; }
public string date{ get; set; }
public int vueltametal { get; set; }
public int amount{ get; set; }
public string station{ get; set; }
public string location{ get; set; }
}
And the form you create in Xamarin is this.
<Label Text="Fuel Purchase"/>
<Label Text="Fecha">
<DatePicker x:Name="Date"/>
<Label Text="Station"/>
<Entry x:Name="Station"/>
<Label Text="Location"/>
<Entry x:Name="Location"/>
<Label Text="Amount"/>
<Entry x:Name="amount" Keyboard="Numeric"/>

Here is a static class that I use for API's. You can change the url to match yours if you only have one. Make sure to step through it and check that all of your "/"'s are in the right spot!
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using NGJS = System.Text.Json;
using System.Threading.Tasks;
namespace TestBCS
{
public class RestService
{
readonly HttpClient client;
public RestService()
{
client = new HttpClient(new HttpClientHandler
{
Proxy = null,
UseProxy = false
});
}
#region GET
public async Task<object> RefreshDataAsync(string url, string qs)
{
Uri uri = new Uri(string.Format(url, qs));
HttpResponseMessage response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
using (var stream = await response.Content.ReadAsStreamAsync())
{
return await NGJS.JsonSerializer.DeserializeAsync<object>(stream);
}
}
//Error Handling here
return null;
}
#endregion
#region POST
static void SerializeJsonIntoStream(object value, Stream stream)
{
using (var sw = new StreamWriter(stream, new UTF8Encoding(false), 1024, true))
using (var jtw = new JsonTextWriter(sw) { Formatting = Formatting.None })
{
var js = new JsonSerializer();
js.Serialize(jtw, value);
jtw.Flush();
}
}
HttpContent CreateHttpContent(object content)
{
HttpContent httpContent = null;
if (content != null)
{
var ms = new MemoryStream();
SerializeJsonIntoStream(content, ms);
ms.Seek(0, SeekOrigin.Begin);
httpContent = new StreamContent(ms);
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
}
return httpContent;
}
public async Task PostStreamAsync(string url, object content)
{
string Url = url;
using (var client = new HttpClient())
using (var request = new HttpRequestMessage(HttpMethod.Post, Url))
using (var httpContent = CreateHttpContent(content))
{
request.Content = httpContent;
using (var response = await client
.SendAsync(request, HttpCompletionOption.ResponseHeadersRead)
.ConfigureAwait(false))
{
response.EnsureSuccessStatusCode();
Debug.WriteLine("Successfully Sent");
}
}
}
#endregion
}
}

Related

How to configure MailKit without password

In ASP.NET Core 6 Web API, I am using MailKit for Email configuration. I am using the SMTP server of my company which doesn't need a password.
I have this:
public class MailSettings
{
public string SmtpServer { get; set; }
public string SenderName { get; set; }
public string SenderEmail { get; set; }
public int SmtpPort { get; set; }
}
Since I am using my company SMTP configuration that needs no password, I use this method to send mails:
public async Task<bool> SendEmailAsync(MailRequest mailRequest)
{
var email = new MimeMessage { Sender = MailboxAddress.Parse(_mailSettings.SenderEmail) };
email.To.Add(MailboxAddress.Parse(mailRequest.ToEmail));
email.Subject = mailRequest.Subject;
var builder = new BodyBuilder();
if (mailRequest.Attachments != null)
{
foreach (var file in mailRequest.Attachments.Where(file => file.Length > 0))
{
byte[] fileBytes;
await using (var ms = new MemoryStream())
{
file.CopyTo(ms);
fileBytes = ms.ToArray();
}
builder.Attachments.Add((file.FileName + Guid.NewGuid().ToString()), fileBytes, ContentType.Parse(file.ContentType));
}
}
builder.HtmlBody = mailRequest.Body;
email.Body = builder.ToMessageBody();
try
{
using var smtp = new SmtpClient();
smtp.Connect(_mailSettings.SmtpServer, _mailSettings.SmtpPort, SecureSocketOptions.StartTls);
smtp.Authenticate(_mailSettings.SenderEmail);
await smtp.SendAsync(email);
smtp.Disconnect(true);
return true;
}
catch (Exception e)
{
_logger.Error(e, e.Source, e.InnerException, e.Message, e.ToString());
return false;
}
}
I got this error:
Argument 1: cannot convert from 'string' to 'MailKit.Security.SaslMechanism'
and it highlights this line of code:
smtp.Authenticate(_mailSettings.SenderEmail);
Expecting me to do it this way:
smtp.Authenticate(_mailSettings.SenderEmail, _mailSettings.Password);
How do I resolve this without password?
Thanks

Aggregate Exception Asp.Net Core 5.0

I have an Mvc project which is based on Asp.Net Core 5.0 . I have my own Core Layer and i have my own Photo,Video uploader method which is based my FileRepo class.
Here is my FileModel class:
public class FileModel
{
public int FileID { get; set; }
public string FileName { get; set; }
public string FileType { get; set; }
public string FileExtension { get; set; }
public string FileSlug { get; set; }
public string FilePath { get; set; }
public byte[] Data { get; set; }
}
Here is my File Uploader method :
public interface IFileUploader
{
Task<FileModel> FileUploadToDatabase(List<IFormFile> files);
Task<FileModel> FileUploadToPath(List<IFormFile> files);
Task<bool> FileDeleteFromPath(int id);
}
public class FileUploader : IFileUploader
{
private FileModel _fileModel;
public FileUploader(FileModel fileModel)
{
_fileModel = fileModel;
}
public async Task<FileModel> FileUploadToDatabase(List<IFormFile> files)
{
foreach (var file in files)
{
var fileName = Path.GetFileNameWithoutExtension(file.FileName);
var extension = Path.GetExtension(file.FileName);
_fileModel = new FileModel
{
FileName = fileName,
FileType = file.ContentType
};
using (var dataStream = new MemoryStream())
{
await file.CopyToAsync(dataStream);
_fileModel.Data = dataStream.ToArray();
}
}
return _fileModel;
}
public async Task<FileModel> FileUploadToPath(List<IFormFile> files)
{
foreach (var file in files)
{
var basePath = Path.Combine(Directory.GetCurrentDirectory() + "\\Files\\");
bool basePathExists = Directory.Exists(basePath);
if (!basePathExists) Directory.CreateDirectory(basePath);
var fileName = Path.GetFileNameWithoutExtension(file.FileName);
var filePath = Path.Combine(basePath, file.FileName);
var extension = Path.GetExtension(file.FileName);
if (!File.Exists(filePath))
{
using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
_fileModel = new FileModel
{
FileName = fileName,
FileType = file.ContentType,
FilePath = filePath
};
}
}
return _fileModel;
}
}
As u guys can see,its a different layer and there is nothing related with my Mvc project.
Im getting error when i add those extension to my Mvc project.
The error says me that :
'Some services are not able to be constructed (Error while validating the service descriptor
'ServiceType: CORE_HBKSOFTWARE.Interfaces.IFileUploader Lifetime: Singleton ImplementationType:
CORE_HBKSOFTWARE.Classes.FileUploader': Unable to resolve service for type
'CORE_HBKSOFTWARE.Models.FileModel' while attempting to activate
'CORE_HBKSOFTWARE.Classes.FileUploader'.)'
I dont know why im getting that error. That FileModel class is seems to okey to me and i still dont know. I allready add my services.AddSingleton<IFileUploader, FileUploader>(); to my Startup.cs .
Thanks for any suggestion !
If you want to use constructor injection to create an instance of FileModel in your FileUploader class you need to register it to the IoC Container. You do that by calling following method in the ConfigureServices method:
services.AddSingleton<FileModel>();
You can also choose a different lifetime by calling AddScoped or AddTransient.

Sending cshtml view mails with mailkit

I am using ASP.NET Core and Mailkit to send emails. Take the following (Basic) code:
var bodyBuilder = new BodyBuilder();
bodyBuilder.HtmlBody = GetBody();
var m = new MimeMessage();
m.To.Add(new MailboxAddress("gurdip.sira#gmail.com"));
m.From.Add(new MailboxAddress("Sender Name", "gurdip.sira#gmail.com"));
string s = GetBody();
// m.Body = bodyBuilder.ToMessageBody();
m.Body = new TextPart(MimeKit.Text.TextFormat.Html) {Text = s};
using (var smtp = new MailKit.Net.Smtp.SmtpClient())
{
smtp.Connect("smtp.gmail.com", 587);
smtp.AuthenticationMechanisms.Remove("XOAUTH2");
smtp.Authenticate("gurdip.sira#gmail.com", "December5!");
smtp.Send(m);
}
The GetBody() method just reads a html document (streamreader).
What I'd like to do is use razor views and cshtml as my emails may contain dynamic content (e.g. an unknown sized collection of certain items).
I can't seem to find definitive documentation on how to do this. The idea is to then just read the cshtml view as plain html but resolve the razor syntax and model variables.
Anyone done anything like this?
One solution is from your controller to pass the content.
public void TestAction(){
var content = PartialView("your_partial_view").ToString();
your_SendEmailFunction(content)
}
So basically you use the partial view as a string that you pass as a content to your method.
Here is a simple demo based on jmal73's comment in Paris Polyzos' blog like below:
1.custom interface:
public interface IViewRenderService
{
Task<string> RenderToStringAsync(string viewName, object model);
}
2.implement interface:
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing;
public class ViewRenderService : IViewRenderService
{
private readonly IRazorViewEngine _razorViewEngine;
private readonly ITempDataProvider _tempDataProvider;
private readonly HttpContext _httpContext;
public ViewRenderService(IRazorViewEngine razorViewEngine,
ITempDataProvider tempDataProvider,
IHttpContextAccessor httpContextAccessor)
{
_razorViewEngine = razorViewEngine;
_tempDataProvider = tempDataProvider;
_httpContext = httpContextAccessor.HttpContext;
}
public async Task<string> RenderToStringAsync(string viewName, object model)
{
var actionContext = new ActionContext(_httpContext, new RouteData(), new ActionDescriptor());
var viewEngineResult = _razorViewEngine.FindView(actionContext, viewName, false);
if (viewEngineResult.View == null || (!viewEngineResult.Success))
{
throw new ArgumentNullException($"Unable to find view '{viewName}'");
}
var view = viewEngineResult.View;
using (var sw = new StringWriter())
{
var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary());
viewDictionary.Model = model;
var tempData = new TempDataDictionary(_httpContext, _tempDataProvider);
var viewContext = new ViewContext(actionContext, view, viewDictionary, tempData, sw, new HtmlHelperOptions());
viewContext.RouteData = _httpContext.GetRouteData(); //set route data here
await view.RenderAsync(viewContext);
return sw.ToString();
}
}
}
3.read .cshtml file and return string:
public class HomeController : Controller
{
private readonly IViewRenderService _viewRenderService;
public HomeController(IViewRenderService viewRenderService)
{
_viewRenderService = viewRenderService;
}
public IActionResult Index()
{
var data = new Users()
{
UserId = 1
};
return View(data);
}
public async Task<IActionResult> Privacy()
{
var data = new Users()
{
UserId = 1
};
var result = await _viewRenderService.RenderToStringAsync("Home/Index", data);
return Content(result);
}
4.Index.cshtml:
#model Users
<form>
<label asp-for="UserId"></label>
<br />
<input asp-for="UserId" class="form-control" maxlength="4" />
<span asp-validation-for="UserId" class="text-danger"></span>
<input type="submit" value="create" />
</form>
5.Register service:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IViewRenderService, ViewRenderService>();

Serialize the Data into JSON

Would like to make this solution as a generic solution wherein instead of Person object, GetJSON Method should accept the generic type which is has the DataContract attribute. Can anybody explain how to go about doing it.
Here is the base code
namespace TestDataContractJsonSerializer
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Json;
public class Program
{
public static void Main(string[] args)
{
List<Person> persons = new List<Person> { new Person("Person1"), new Person("Person2") };
var strJSON = from p in persons select GetJSON(p);
Console.WriteLine("In JSON Format: ");
foreach (string str in strJSON)
{
Console.WriteLine(" {0}", str);
}
Console.ReadKey();
}
private static string GetJSON(Person p)
{
if (p != null)
{
MemoryStream stream = new MemoryStream();
DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(Person));
dataContractJsonSerializer.WriteObject(stream, p);
stream.Position = 0;
StreamReader sr = new StreamReader(stream);
return sr.ReadToEnd();
}
return string.Empty;
}
}
[DataContract]
public class Person
{
public Person(string name)
{
this.Name = name;
}
[DataMember]
public string Name { get; private set; }
}
}
It would look something like this in the very basic case. You'd probably need to add some special casing and/or error handling, for instance if the type T is not serializable.
private static string GetJSON<T>(T objToSerialize)
{
if (objToSerialize != null)
{
MemoryStream stream = new MemoryStream();
DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(objToSerialize.GetType());
dataContractJsonSerializer.WriteObject(stream, objToSerialize);
stream.Position = 0;
StreamReader sr = new StreamReader(stream);
return sr.ReadToEnd();
}
return string.Empty;
}

Custom model binder with inheritance using Web API and RavenDB

I'm developing a simple web app where I need to bind all types implementing and interface of a specific type. My interface has one single property like this
public interface IContent {
string Id { get;set; }
}
a common class using this interface would look like this
public class Article : IContent {
public string Id { get;set; }
public string Heading { get;set; }
}
to be clean here the article class is just one of many different classes implementing IContent so therefor I need a generic way of storing and updating these types.
So in my controller I have the put method like this
public void Put(string id, [System.Web.Http.ModelBinding.ModelBinder(typeof(ContentModelBinder))] IContent value)
{
// Store the updated object in ravendb
}
and the ContentBinder
public class ContentModelBinder : System.Web.Http.ModelBinding.IModelBinder {
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) {
actionContext.ControllerContext.Request.Content.ReadAsAsync<Article>().ContinueWith(task =>
{
Article model = task.Result;
bindingContext.Model = model;
});
return true;
}
}
The code above does not work because it does not seem to get hold of the Heading property even though if I use the default model binder it binds the Heading correctly.
So, in the BindModel method I guess I need to load the correct object from ravendb based on the Id and then update the complex object using some kind of default model binder or so? This is where I need some help.
Marcus, following is an example which would work fine for both Json and Xml formatter.
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Runtime.Serialization;
using System.Web.Http;
using System.Web.Http.SelfHost;
namespace Service
{
class Service
{
private static HttpSelfHostServer server = null;
private static string baseAddress = string.Format("http://{0}:9095/", Environment.MachineName);
static void Main(string[] args)
{
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(baseAddress);
config.Routes.MapHttpRoute("Default", "api/{controller}/{id}", new { id = RouteParameter.Optional });
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
try
{
server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();
Console.WriteLine("Service listenting at: {0} ...", baseAddress);
TestWithHttpClient("application/xml");
TestWithHttpClient("application/json");
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine("Exception Details:\n{0}", ex.ToString());
}
finally
{
if (server != null)
{
server.CloseAsync().Wait();
}
}
}
private static void TestWithHttpClient(string mediaType)
{
HttpClient client = new HttpClient();
MediaTypeFormatter formatter = null;
// NOTE: following any settings on the following formatters should match
// to the settings that the service's formatters have.
if (mediaType == "application/xml")
{
formatter = new XmlMediaTypeFormatter();
}
else if (mediaType == "application/json")
{
JsonMediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();
jsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
formatter = jsonFormatter;
}
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = new Uri(baseAddress + "api/students");
request.Method = HttpMethod.Get;
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(mediaType));
HttpResponseMessage response = client.SendAsync(request).Result;
Student std = response.Content.ReadAsAsync<Student>().Result;
Console.WriteLine("GET data in '{0}' format", mediaType);
if (StudentsController.CONSTANT_STUDENT.Equals(std))
{
Console.WriteLine("both are equal");
}
client = new HttpClient();
request = new HttpRequestMessage();
request.RequestUri = new Uri(baseAddress + "api/students");
request.Method = HttpMethod.Post;
request.Content = new ObjectContent<Person>(StudentsController.CONSTANT_STUDENT, formatter);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(mediaType));
Student std1 = client.SendAsync(request).Result.Content.ReadAsAsync<Student>().Result;
Console.WriteLine("POST and receive data in '{0}' format", mediaType);
if (StudentsController.CONSTANT_STUDENT.Equals(std1))
{
Console.WriteLine("both are equal");
}
}
}
public class StudentsController : ApiController
{
public static readonly Student CONSTANT_STUDENT = new Student() { Id = 1, Name = "John", EnrolledCourses = new List<string>() { "maths", "physics" } };
public Person Get()
{
return CONSTANT_STUDENT;
}
// NOTE: specifying FromBody here is not required. By default complextypes are bound
// by formatters which read the body
public Person Post([FromBody] Person person)
{
if (!ModelState.IsValid)
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, this.ModelState));
}
return person;
}
}
[DataContract]
[KnownType(typeof(Student))]
public abstract class Person : IEquatable<Person>
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
// this is ignored
public DateTime DateOfBirth { get; set; }
public bool Equals(Person other)
{
if (other == null)
return false;
if (ReferenceEquals(this, other))
return true;
if (this.Id != other.Id)
return false;
if (this.Name != other.Name)
return false;
return true;
}
}
[DataContract]
public class Student : Person, IEquatable<Student>
{
[DataMember]
public List<string> EnrolledCourses { get; set; }
public bool Equals(Student other)
{
if (!base.Equals(other))
{
return false;
}
if (this.EnrolledCourses == null && other.EnrolledCourses == null)
{
return true;
}
if ((this.EnrolledCourses == null && other.EnrolledCourses != null) ||
(this.EnrolledCourses != null && other.EnrolledCourses == null))
return false;
if (this.EnrolledCourses.Count != other.EnrolledCourses.Count)
return false;
for (int i = 0; i < this.EnrolledCourses.Count; i++)
{
if (this.EnrolledCourses[i] != other.EnrolledCourses[i])
return false;
}
return true;
}
}
}
I used #kiran-challa solution and added TypeNameHandling on Json media type formatter's SerializerSettings.