embedio - Post pdf with embedio in xamarin app - status is OK but the stream is 0 - xamarin

I have been using embedio and I would like to post pdf and display it in my Webview in my xamarin application. The pdf is as embedded resource in my application. It all seems to be ok, but the stream position is 0, however the status is 200 ok. and then At readTimeout I see
System.InvalidOperationException: Timeouts are not supported on this stream.
at System.IO.Stream.get_ReadTimeout () [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corert/src/System.Private.CoreLib/shared…
My initialization of embedio
public App()
{
Task.Factory.StartNew(async () =>
{
using (var server = new WebServer(HttpListenerMode.EmbedIO, "http://*:8089"))
{
Assembly assembly = typeof(App).Assembly;
server.WithLocalSessionManager();
server.WithWebApi("/api", m => m.WithController(() => new PdfSourceController()));
server.WithEmbeddedResources("/", assembly, "TestApp.html");
await server.RunAsync();
}
});
MainPage = new NavigationPage(new MainPage());
}
My controller
public class PdfSourceController : WebApiController
{
public PdfSourceController() : base()
{
}
[Route(HttpVerbs.Post, "/pdf")]
public async Task UploadFile()
{
var parser = new MultipartFormDataContent();
var fileContent = new StreamContent(new EmbeddedResourceDataStream("Assets/TestDoc.pdf").GetDataStream());
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{Name = "result", FileName = $"\"{"test"}\""};
fileContent.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data");
parser.Add(fileContent);
}
private async Task TestPost()
{
try
{
var handler = new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate ,
};
using (var client = new HttpClient(handler))
{
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("*"));
using (var response = await client.PostAsync($"{DefaultUrl}api/pdf", new MultipartFormDataContent() ).ConfigureAwait(false)) // calling controller?
{
response.Content.Headers.ContentType = new MediaTypeHeaderValue("api/pdf"); // stating what media type?
var responseString = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
response.Content = new StreamContent(responseString);
Pdf = ImageSource.FromStream(() => responseString);
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}

Related

Geolocation functionality of Xamarin Essentials wrong location results

I am using the Geolocation functionality of Xamarin Essentials in my app as a foreground service running all the time and I have noticed on several devices that I sometimes get locations which are really far away from where they should actually be, looking like this (the marked location is far away from the real location):
public async Task Run(CancellationToken token)
{
await Task.Run(async () => {
while (!stopping)
{
token.ThrowIfCancellationRequested();
try
{
await Task.Delay(2000);
var request = new GeolocationRequest(GeolocationAccuracy.Best);
var location = await Geolocation.GetLocationAsync(request);
if (location != null)
{
var message = new LocationMessage
{
Latitude = location.Latitude,
Longitude = location.Longitude
};
Device.BeginInvokeOnMainThread(() =>
{
MessagingCenter.Send<LocationMessage>(message, "Location");
});
}
}
catch (Exception ex)
{
Device.BeginInvokeOnMainThread(() =>
{
var errormessage = new LocationErrorMessage();
MessagingCenter.Send<LocationErrorMessage>(errormessage, "LocationError");
});
}
}
return;
}, token);
}
result

Unable to complete MSAL login in Xamarin app

I'm trying to get my feet wet with Xamarin and I'm having trouble adding in my organization's login. The screen shot below is as far as I can get attempting to login. When I click "Continue" the same page just loads again. Not really sure what's going on.
The image is the screen I'm stuck on.
I've added code that represents the app class and the code behind for the XAML page attempting to login, leaving out what I "think" is irrelvant.
Any suggestions?
public partial class App : Application
{
public static string AzureBackendUrl =
DeviceInfo.Platform == DevicePlatform.Android ? "http://10.0.2.2:5000" : "http://localhost:5000";
public static bool UseMockDataStore = true;
public static IPublicClientApplication PCA = null;
public static string ClientID = "CLIENT_ID";
public static string[] Scopes = { "User.Read" };
public static string Username = string.Empty;
public static object ParentWindow { get; set; }
public App()
{
InitializeComponent();
if (UseMockDataStore)
DependencyService.Register<MockDataStore>();
else
DependencyService.Register<AzureDataStore>();
PCA = PublicClientApplicationBuilder.Create(ClientID)
.WithRedirectUri($"msal{App.ClientID}://auth")
//.WithParentActivityOrWindow(() => App.ParentWindow)
.Build();
MainPage = new MSAL_Example();
}
}
public partial class MSAL_Example : ContentPage
{
public static string tenant_name = "MY_TENANT_NAME";
public MSAL_Example()
{
InitializeComponent();
App.ParentWindow = this;
}
public async Task SignOutAsync()
{
IEnumerable<IAccount> accounts = await App.PCA.GetAccountsAsync();
try
{
while (accounts.Any())
{
await App.PCA.RemoveAsync(accounts.FirstOrDefault());
accounts = await App.PCA.GetAccountsAsync();
}
slUser.IsVisible = false;
Device.BeginInvokeOnMainThread(() => { btnSignInSignOut.Text = "Sign in"; });
}
catch (Exception ex)
{
Debug.WriteLine("\tERROR {0}", ex.Message);
}
}
public async Task SignInAsync()
{
AuthenticationResult authResult = null;
IEnumerable<IAccount> accounts = await App.PCA.GetAccountsAsync();
// let's see if we have a user in our belly already
try
{
IAccount firstAccount = accounts.FirstOrDefault();
authResult = await App.PCA.AcquireTokenSilent(App.Scopes, firstAccount)
.ExecuteAsync();
await RefreshUserDataAsync(authResult.AccessToken).ConfigureAwait(false);
Device.BeginInvokeOnMainThread(() => { btnSignInSignOut.Text = "Sign out"; });
}
catch (MsalUiRequiredException ex)
{
try
{
authResult = await App.PCA.AcquireTokenInteractive(App.Scopes)
.WithParentActivityOrWindow(App.ParentWindow)
.WithAuthority("https://login.microsoftonline.com/" + tenant_name)
.ExecuteAsync();
await RefreshUserDataAsync(authResult.AccessToken);
Device.BeginInvokeOnMainThread(() => { btnSignInSignOut.Text = "Sign out"; });
}
catch (Exception ex2)
{
Debug.WriteLine("\tERROR {0}", ex2.Message);
}
}
}
public async Task RefreshUserDataAsync(string token)
{
//get data from API
HttpClient client = new HttpClient();
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me");
message.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", token);
HttpResponseMessage response = await client.SendAsync(message);
string responseString = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
JObject user = JObject.Parse(responseString);
slUser.IsVisible = true;
Device.BeginInvokeOnMainThread(() =>
{
lblDisplayName.Text = user["displayName"].ToString();
lblGivenName.Text = user["givenName"].ToString();
lblId.Text = user["id"].ToString();
lblSurname.Text = user["surname"].ToString();
lblUserPrincipalName.Text = user["userPrincipalName"].ToString();
// just in case
btnSignInSignOut.Text = "Sign out";
});
}
else
{
await DisplayAlert("Something went wrong with the API call", responseString, "Dismiss");
}
}
}

ReplyToId' cannot be null

This exception is continuously throwing. This started since i updated botframework to 3.5.3.
Code :
MessagesController :
await Conversation.SendAsync(activity, () => new DefaultDialog());
Than in my DefaultDialog :
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
var msg = await argument;
await Helper.CallMenu(context, msg);
In CallMenu function :
internal static async Task CallMenu(IDialogContext context, IMessageActivity msg)
{
await MenuFirstPart(context, msg);
In MenuFirstPart function :
internal static async Task MenuFirstPart(IDialogContext context, IMessageActivity msg)
{
await context.PostAsync("I can assist you with : ");
msg.AttachmentLayout = AttachmentLayoutTypes.Carousel;
msg.Attachments = new List<Attachment>();
ThumbnailCard thumbnailCard = new ThumbnailCard()
{
Buttons = new List<CardAction>
{
new CardAction ()
{
Value = "Method_News",
Type = "postBack",
Title = "News"
},
new CardAction()
{
Value = "Method_About",
Type = "postBack",
Title = "About"
},
new CardAction ()
{
Value = "Method_Help",
Type = "postBack",
Title = "Help"
},
},
};
msg.Attachments.Add(thumbnailCard.ToAttachment());
await context.PostAsync(msg);
}
Exception is thrown when context is trying to post msg.
Any help ? Or how to downgrade my bot to 3.5.0. This worked fine there ...
You are using the incoming message (msg) and sending that back.
You need to create a new message instead. Use the following:
var reply = context.MakeMessage();

web api - asp.net identity token expires even for the subsequent request

I am using asp.net identity for the token based authentication in web api.
For refresh token, I've implemented based on the following link
http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/
I've added the following two classes and mentioned in the start up configuration.
From the ui I've called with username and password alone through the api
http://domain/token
When I call the above api, the request directly goes to the method ValidateClientAuthentication.
But in this method the logic is, we need to send the client id and client secret.
How do we know these two before the user login for the specific user?
I thought the work flow should be like, we need to check username and password against database and should generate the access token and refresh token.
But here where do i do this logic.
What is the work flow of this system mentioned in the sample?
Before this system, I'll call the Common/login api in my application, and after successful verification,
I'll call the code to make the user as logged in
var userIdentity=await user.GenerateUserIdentityAsync(UserManager);
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, userIdentity);
After the above code, I'll generate the access token from the user identity.
I've tried many times with the following implementation and fed up with the flow.
Help me regarding the logic and the flow mentioned here.
SimpleAuthorizationServerProvider
namespace AngularJSAuthentication.API.Providers
{
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
string clientId = string.Empty;
string clientSecret = string.Empty;
Client client = null;
if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
{
context.TryGetFormCredentials(out clientId, out clientSecret);
}
if (context.ClientId == null)
{
//Remove the comments from the below line context.SetError, and invalidate context
//if you want to force sending clientId/secrects once obtain access tokens.
context.Validated();
//context.SetError("invalid_clientId", "ClientId should be sent.");
return Task.FromResult<object>(null);
}
using (AuthRepository _repo = new AuthRepository())
{
client = _repo.FindClient(context.ClientId);
}
if (client == null)
{
context.SetError("invalid_clientId", string.Format("Client '{0}' is not registered in the system.", context.ClientId));
return Task.FromResult<object>(null);
}
if (client.ApplicationType == Models.ApplicationTypes.NativeConfidential)
{
if (string.IsNullOrWhiteSpace(clientSecret))
{
context.SetError("invalid_clientId", "Client secret should be sent.");
return Task.FromResult<object>(null);
}
else
{
if (client.Secret != Helper.GetHash(clientSecret))
{
context.SetError("invalid_clientId", "Client secret is invalid.");
return Task.FromResult<object>(null);
}
}
}
if (!client.Active)
{
context.SetError("invalid_clientId", "Client is inactive.");
return Task.FromResult<object>(null);
}
context.OwinContext.Set<string>("as:clientAllowedOrigin", client.AllowedOrigin);
context.OwinContext.Set<string>("as:clientRefreshTokenLifeTime", client.RefreshTokenLifeTime.ToString());
context.Validated();
return Task.FromResult<object>(null);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");
if (allowedOrigin == null) allowedOrigin = "*";
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
using (AuthRepository _repo = new AuthRepository())
{
IdentityUser user = await _repo.FindUser(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
identity.AddClaim(new Claim(ClaimTypes.Role, "user"));
identity.AddClaim(new Claim("sub", context.UserName));
var props = new AuthenticationProperties(new Dictionary<string, string>
{
{
"as:client_id", (context.ClientId == null) ? string.Empty : context.ClientId
},
{
"userName", context.UserName
}
});
var ticket = new AuthenticationTicket(identity, props);
context.Validated(ticket);
}
public override Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
{
var originalClient = context.Ticket.Properties.Dictionary["as:client_id"];
var currentClient = context.ClientId;
if (originalClient != currentClient)
{
context.SetError("invalid_clientId", "Refresh token is issued to a different clientId.");
return Task.FromResult<object>(null);
}
// Change auth ticket for refresh token requests
var newIdentity = new ClaimsIdentity(context.Ticket.Identity);
var newClaim = newIdentity.Claims.Where(c => c.Type == "newClaim").FirstOrDefault();
if (newClaim != null)
{
newIdentity.RemoveClaim(newClaim);
}
newIdentity.AddClaim(new Claim("newClaim", "newValue"));
var newTicket = new AuthenticationTicket(newIdentity, context.Ticket.Properties);
context.Validated(newTicket);
return Task.FromResult<object>(null);
}
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}
}
}
SimpleRefreshTokenProvider
namespace AngularJSAuthentication.API.Providers
{
public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider
{
public async Task CreateAsync(AuthenticationTokenCreateContext context)
{
var clientid = context.Ticket.Properties.Dictionary["as:client_id"];
if (string.IsNullOrEmpty(clientid))
{
return;
}
var refreshTokenId = Guid.NewGuid().ToString("n");
using (AuthRepository _repo = new AuthRepository())
{
var refreshTokenLifeTime = context.OwinContext.Get<string>("as:clientRefreshTokenLifeTime");
var token = new RefreshToken()
{
Id = Helper.GetHash(refreshTokenId),
ClientId = clientid,
Subject = context.Ticket.Identity.Name,
IssuedUtc = DateTime.UtcNow,
ExpiresUtc = DateTime.UtcNow.AddMinutes(Convert.ToDouble(refreshTokenLifeTime))
};
context.Ticket.Properties.IssuedUtc = token.IssuedUtc;
context.Ticket.Properties.ExpiresUtc = token.ExpiresUtc;
token.ProtectedTicket = context.SerializeTicket();
var result = await _repo.AddRefreshToken(token);
if (result)
{
context.SetToken(refreshTokenId);
}
}
}
public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
{
var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
string hashedTokenId = Helper.GetHash(context.Token);
using (AuthRepository _repo = new AuthRepository())
{
var refreshToken = await _repo.FindRefreshToken(hashedTokenId);
if (refreshToken != null )
{
//Get protectedTicket from refreshToken class
context.DeserializeTicket(refreshToken.ProtectedTicket);
var result = await _repo.RemoveRefreshToken(hashedTokenId);
}
}
}
public void Create(AuthenticationTokenCreateContext context)
{
throw new NotImplementedException();
}
public void Receive(AuthenticationTokenReceiveContext context)
{
throw new NotImplementedException();
}
}
}
How about using refresh tokens and storing them in a database, like in these two examples:
http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/
http://leastprivilege.com/2013/11/15/adding-refresh-tokens-to-a-web-api-v2-authorization-server/
As broadly described in the first link, you can create your own token provider implementation to handle token refresh:
public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider
{
public async Task CreateAsync(AuthenticationTokenCreateContext context)
{
var clientid = context.Ticket.Properties.Dictionary["as:client_id"];
if (string.IsNullOrEmpty(clientid))
{
return;
}
var refreshTokenId = Guid.NewGuid().ToString("n");
using (AuthRepository _repo = new AuthRepository())
{
var refreshTokenLifeTime = context.OwinContext.Get<string>("as:clientRefreshTokenLifeTime");
var token = new RefreshToken()
{
Id = Helper.GetHash(refreshTokenId),
ClientId = clientid,
Subject = context.Ticket.Identity.Name,
IssuedUtc = DateTime.UtcNow,
ExpiresUtc = DateTime.UtcNow.AddMinutes(Convert.ToDouble(refreshTokenLifeTime))
};
context.Ticket.Properties.IssuedUtc = token.IssuedUtc;
context.Ticket.Properties.ExpiresUtc = token.ExpiresUtc;
token.ProtectedTicket = context.SerializeTicket();
var result = await _repo.AddRefreshToken(token);
if (result)
{
context.SetToken(refreshTokenId);
}
}
}
}

Xamarin Forms Grid - change cell view via button

I have a page in which I display two different charts, depending on a button click. At the moment I change charts this way:
protected void ClickedChangeChart()
{
if (chartType == true)
{
chartType = false;
Navigation.PushAsync (new MainPage (false));
}
else
{
chartType = true;
Navigation.PushAsync (new MainPage (true));
}
}
chartType is a bool and depending on it's value I choose which chart to load using this statement in OnAppearing():
protected override async void OnAppearing ()
{
// some code
ChartView chartView = new ChartView
{
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
HeightRequest = 300,
WidthRequest = 400
};
if (chartType == true)//true = candle
{
candleModel = new CandleModel ();
chartView.Model = await candleModel.GetModel ();
}
else if(chartType == false) //false = line
{
lineModel = new LineModel ();
chartView.Model = await lineModel.GetModel ();
}
//here I create a grid, add some children to it and the add the chartView
grid.Children.Add (chartView, 1, 6, 1, 3);
Content = grid;
}
The problem is that when I want to switch the charts I have to reload the whole page, which isn't what I want. How can I make it so when I click a button I calls a function which switches the model for the chart? I suppose it will be something like this, but I can't get it to work:
public async void ClickedButton()
{
grid.Children.Remove(chartView);
if (chartType == true)
{
candleModel = new CandleModel ();
chartView.Model = await candleModel.GetModel ();
}
else if(chartType == false)
{
lineModel = new LineModel ();
chartView.Model = await lineModel.GetModel ();
}
grid.Children.Add(chartView);
}
UPDATE:
Using Daniel Luberda's solution, I managed to get it to work with this:
btnChartType.Clicked += async delegate {
Device.BeginInvokeOnMainThread (async () => {
grid.Children.Remove (chartView);
if (isCandle == true) {
candleModel = new CandleModel ();
chartView.Model = await candleModel.GetModel ();
isCandle = false;
} else if (isCandle == false) {
lineModel = new LineModel ();
chartView.Model = await lineModel.GetModel ();
isCandle = true;
}
grid.Children.Add (chartView, 1, 6, 1, 3);
});
};
You can't get it to work because you have an async method which means that you're doing it on another thread. You can change UI only from UI thread. Also async void will swallow all exceptions, it's better to use async Task instead.
// THAT WILL WORK
public async void ClickedButton() // but public async Task would be better
{
Device.BeginInvokeOnMainThread(async () => {
grid.Children.Remove(chartView);
if (chartType == true)
{
candleModel = new CandleModel ();
chartView.Model = await candleModel.GetModel ();
}
else if(chartType == false)
{
lineModel = new LineModel ();
chartView.Model = await lineModel.GetModel ();
}
grid.Children.Add(chartView);
});
}

Resources