Xamarin Form's HttpWebRequest no timeout property? - xamarin.forms

Am using HttpWebRequest to make HTTP calls, i see it doesn't have a Timeout property ?
For example:
HttpWebRequest request = WebRequest.Create(aWebUrl) as HttpWebRequest;
request.ContentType = "application/json";
request.Method = "GET";
Thanks

I think you can take a look to James Montemagno's plugin
there is a Utils that help you to check if an async call goes in timeout. I think you can use it with your Web Request.
namespace MvvmHelpers
{
/// <summary>
/// Extension Utils
/// </summary>
public static class Utils
{
/// <summary>
/// Task extension to add a timeout.
/// </summary>
/// <returns>The task with timeout.</returns>
/// <param name="task">Task.</param>
/// <param name="timeoutInMilliseconds">Timeout duration in Milliseconds.</param>
/// <typeparam name="T">The 1st type parameter.</typeparam>
public async static Task<T> WithTimeout<T>(this Task<T> task, int timeoutInMilliseconds)
{
var retTask = await Task.WhenAny(task, Task.Delay(timeoutInMilliseconds))
.ConfigureAwait(false);
if (retTask is Task<T>)
return task.Result;
return default(T);
}
/// <summary>
/// Task extension to add a timeout.
/// </summary>
/// <returns>The task with timeout.</returns>
/// <param name="task">Task.</param>
/// <param name="timeout">Timeout Duration.</param>
/// <typeparam name="T">The 1st type parameter.</typeparam>
public static Task<T> WithTimeout<T>(this Task<T> task, TimeSpan timeout) =>
WithTimeout(task, (int)timeout.TotalMilliseconds);
}
}
you can find an explanation of it in this video Channel 9 MVVM helper
Otherwise you can use HttpClient that has a "Timeout" property
Timeout

Related

Reduce IdentityServer4 access_token length by removing claims in profile service

I am working on IdentityServer4 application. The generated Access_token length is becoming too lengthy due to the claim value added to the context.IssuedClaims. I tried to remove claim type called "entity" and it helps in reducing the access_token length. But its removing the claim from ClaimsPrincipal as well. Is there a way I can add this claim back to my ClaimsPrincipal so that I can access it from all my client applications? Currently I am invoking a separate API to get the claim back every time. Below is the code from my ProfileService where I am filtering the claim.
public async Task GetProfileDataAsync(IdentityServer4.Models.ProfileDataRequestContext context)
{
var user = await _userManager.GetUserAsync(context.Subject);
var principal = await _claimsFactory.CreateAsync(user);
//Retrieve all the claims associated with the user
var claims = from claimsdata in principal.Claims select new System.Security.Claims.Claim(claimsdata.Type, claimsdata.Value);
//Exclude claim type "entity" since its huge in numbers and causing access_token size to grow
var claimsWithoutEntity = claims.Where(x => x.Type != "entity");
context.IssuedClaims.AddRange(claimsWithoutEntity);
var roleClaims = _roleService.GetRoleClaims(user);
context.IssuedClaims.AddRange(roleClaims);
}
A different alternative to reduce the cookie size without modifying the access token is to create a SessionStore, and you can set it using the SessionStore parameter here:
}).AddCookie(options =>
{
...
options.SessionStore = new MySessionStore();
})
What does a SessionStore do?
See this picture, taken from one of my training classes:
Here's a sample in-memory store
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Serilog;
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
namespace SessionStore
{
/// <summary>
/// MySessionStore
///
/// Custom session store, to hold the tokens in memory instead of storing them inside the Cookie.
///
/// This provides an abstract storage mechanic to preserve identity information on the server while
/// only sending a simple identifier key to the client. This is most commonly used to mitigate issues
/// with serializing large identities into cookies.
///
/// TODO:
/// - Needs logic to remove older items, otherwise we might run out of memory here.
/// - Use the MemoryCache instead of a dictionary?
///
/// Written by Tore Nestenius to be used in the IdentityServer in production training class.
/// https://www.tn-data.se
///
/// </summary>
internal class MySessionStore : ITicketStore
{
private readonly Serilog.ILogger _logger;
private readonly ConcurrentDictionary<string, AuthenticationTicket> mytickets = new();
public MySessionStore()
{
_logger = Log.Logger;
}
/// <summary>
/// Remove the identity associated with the given key.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public Task RemoveAsync(string key)
{
_logger.Debug("MySessionStore.RemoveAsync Key=" + key);
if (mytickets.ContainsKey(key))
{
mytickets.TryRemove(key, out _);
}
return Task.FromResult(0);
}
/// <summary>
/// Tells the store that the given identity should be updated.
/// </summary>
/// <param name="key"></param>
/// <param name="ticket"></param>
/// <returns></returns>
public Task RenewAsync(string key, AuthenticationTicket ticket)
{
_logger.Debug("MySessionStore.RenewAsync Key=" + key + ", ticket = " + ticket.AuthenticationScheme);
mytickets[key] = ticket;
return Task.FromResult(false);
}
/// <summary>
/// Retrieves an identity from the store for the given key.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public Task<AuthenticationTicket> RetrieveAsync(string key)
{
_logger.Error("MySessionStore.RetrieveAsync Key=" + key);
if (mytickets.ContainsKey(key))
{
var ticket = mytickets[key];
return Task.FromResult(ticket);
}
else
{
return Task.FromResult((AuthenticationTicket)null!);
}
}
/// <summary>
/// Store the identity ticket and return the associated key.
/// </summary>
/// <param name="ticket"></param>
/// <returns></returns>
public Task<string> StoreAsync(AuthenticationTicket ticket)
{
//Only add one at the time to avoid race conditions
lock(this)
{
//Make sure the key is does not already exist in the dictionary
bool result = false;
string key;
do
{
key = Guid.NewGuid().ToString();
result = mytickets.TryAdd(key, ticket);
} while (result == false);
string username = ticket?.Principal?.Identity?.Name ?? "Unknown";
_logger.Debug("MySessionStore.StoreAsync ticket=" + username + ", key=" + key);
return Task.FromResult(key);
}
}
}
}

When do you need a parameterless constructor on a Command/DTO object for an API call?

I am getting the following exception thrown: "System.NotSupportedException: Deserialization of reference
types without parameterless constructor is not supported."
It is JSON being passed into the controller.
When do you need a parameterless constructor vs. one with parameters?
I am using ASP.NetCore.App.Ref 3.1.3 and NetCore.App.Ref 3.1.0.
Here is the class that it is saying needs a parameterless constructor:
public class JobApplicationStatusModel : BaseEntityModel
{
/// <summary>
///JobApplicationStatus ID
/// </summary>
public int Id { get; set; }
/// <summary>
/// Description/Name of Status.
/// </summary>
public string StatusDescription { get; set; }
/// <summary>
/// Main constructor
/// </summary>
/// <param name="id">JobApplication StatusID</param>
/// <param name="statusDescription">Status Description</param>
public JobApplicationStatusModel(int id, string statusDescription)
{
Id = id;
StatusDescription = statusDescription ?? throw new ArgumentNullException(nameof(statusDescription));
}
/// <summary>
/// Returns an enumeration of all atomic values.
/// </summary>
/// <returns>An enumeration of all atomic values.</returns>
protected override IEnumerable<object> GetAtomicValues()
{
// Using a yield return statement to return each element one at a time
yield return Id;
yield return StatusDescription;
}
}

What's the difference between context.Get() and its generic version?

I'm trying to get familiar with OWIN and there are a lot of things that confuse me. For example, in partial startup.cs class I register context callback via
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
What's the difference? Why do we need that generic method?
I can get that context like this:
context.Get<ApplicationDbContext>())
context.GetUserManager<ApplicationUserManager>()
What's the difference between the Get and GetUserManager methods? Why can't I just call context.Get for ApplicationUserManager?
There is no difference between Get<UserManager> and GetUserManager<UserManager>
Here's the source code for both...
/// <summary>
/// Retrieves an object from the OwinContext using a key based on the AssemblyQualified type name
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="context"></param>
/// <returns></returns>
public static T Get<T>(this IOwinContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
return context.Get<T>(GetKey(typeof (T)));
}
/// <summary>
/// Get the user manager from the context
/// </summary>
/// <typeparam name="TManager"></typeparam>
/// <param name="context"></param>
/// <returns></returns>
public static TManager GetUserManager<TManager>(this IOwinContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
return context.Get<TManager>();
}

Web APIs methods with Warnings

I have this method in an API that does POST for creating a record, but before inserting that record in DB there are some validations that i must do, I might come back with warnings and I need to return back these warnings to the client to confirm back.
what is the best way to do that in Web API's? or should i split the method into 2, one for validation and one for saving?
Set up your Web Api the following way.
[HttpPost]
public IHttpActionResult DoStuff(object item)
{
if(!validate(item))
{
return this.BadRequest("Validation failed blablabla");
}
else
{
//insert logic
}
return this.Ok();
}
What happens is you validate the object you send to the API. When it fails to validate you return the request was not correct, with the message you specified.
When the validation succeeds the insert logic is called and you return a OK result when it succeeds.
I create and use a wrapper which would contain object to be bound to ui, messages (error or validation or warning) and total.
/// <summary>
/// Class for the Repository response object
/// </summary>
/// <typeparam name="T"></typeparam>
public class CLSResponse<T>
{
/// <summary>
/// Gets or sets the messages to be returned in the response.
/// </summary>
/// <value>The messages.</value>
public IEnumerable<KeyValuePair<string, string>> Messages {
get { return m_Messages; }
set { m_Messages = value; }
}
private IEnumerable<KeyValuePair<string, string>> m_Messages;
/// <summary>
/// Gets or sets the service model to be returned in the response.
/// </summary>
/// <value>The service model.</value>
public T ServiceModel {
get { return m_ServiceModel; }
set { m_ServiceModel = value; }
}
private T m_ServiceModel;
/// <summary>
/// Gets or sets the totalitems.
/// </summary>
/// <value>The TotalItems.</value>
public int TotalItems {
get { return m_TotalItems; }
set { m_TotalItems = value; }
}
private int m_TotalItems;
/// <summary>
/// Gets and Sets the Message Type based on the MessageType Struct
/// </summary>
public string MessagesType;
}
/// <summary>
/// Struct for MessageTypes to be returned with messages, in the response object
/// </summary>
public struct MessagesType
{
/// <summary>
/// Validation
/// </summary>
public static string Validation = "Validation";
/// <summary>
/// Warning
/// </summary>
public static string Warning = "Warning";
/// <summary>
/// Error
/// </summary>
public static string Error = "Error";
/// <summary>
/// Unauthorized
/// </summary>
public static string UnAuthorized = "Unauthorized";
}
Then in your repository layer or logic layer
public CLSResponse<bool> CreateUser(string request)
{
var messages = new List<KeyValuePair<string, string>>();
try
{
//Do something
if (!validation)
{
messages.Add(MessagesType.Validation, "Invalid");
return new CLSResponse<bool> {
ServiceModel = false,
Messages = messages,
MessagesType = MessagesType.Validation
};
}
else {
return new CLSResponse<bool> {
ServiceModel = true,
Messages = messages,
MessagesType = MessagesType.Error
};
}
}
catch (Exception ex)
{
messages.Add(MessagesType.Error, "UpdateFailed");
return new CLSResponse<bool> {
ServiceModel = false,
Messages = messages,
MessagesType = MessagesType.Error
};
}
}
Now on controller,
[HttpPost]
public HttpResponseMessage<CLSResponse<bool>> CreateUser(string input)
{
var res = LogicLayer.CreateUser(input);
//Check for res.MessageType and set the status code
if (res.MessagesType = MessagesType.Validation)
{
return Request.CreateResponse<CLSResponse<bool>>(HttpStatusCode.PreconditionFailed, res);
}
}
This way your response object still has the warning you added in logic layer and depending on the status code returned, you can handle those messages on client side.

signalR OnDisconnected() cancel task

When a page loads I start a new task in my hub. This task sends data to a browser updating a certain html elements. When I browse away from the page I want to stop the task.
The problem is that before the task is stopped (due to it's sleep argument), a new tokenSource = new CancellationTokenSource();
is set before the previous instance of this task had a chance to stop.
What i'm trying to do is to have the task stop when browsing away from the page to a different page that is not requiring signalR. BUT maybe, not stop it if it's only a refresh of the same page. Not sure how to do it. To sum it up, I want to guarantee that only 1 instance of this task is running (AND only on the page that requires it/or have a listener)
any info greatly appreciated.
thanks
CODE:
public class TaskActionStatus : Hub
{
#region Static Fields
/// <summary>
/// The token source.
/// </summary>
private static CancellationTokenSource tokenSource;
/// <summary>
/// The url string.
/// </summary>
private static string url = string.Empty;
#endregion
#region Public Methods and Operators
/// <summary>
/// The get tasks status.
/// </summary>
/// <param name="siteId">
/// The site id.
/// </param>
/// <param name="location"></param>
public void GetTasksStatus(int? siteId)
{
var taskRepository = UnityContainerSetup.Container.Resolve<ITaskRepository>();
tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
// init task for checking task statuses
var tasksItem = new DownloadTaskItem();
// start task only if at least one listener
if (UserHandler.ConnectedIds.Count < 2 && !taskRepository.IsTasksStatusAsyncRunning())
{
taskRepository.GetTasksStatusAsync(siteId, tasksItem, ct);
// subscribe to event [ listener ]
tasksItem.Changed += this.UpdateTasksStatus;
}
else tokenSource.Cancel();
}
/// <summary>
/// The on connected.
/// </summary>
/// <returns>
/// The <see cref="Task"/>.
/// </returns>
public override Task OnConnected()
{
UserHandler.ConnectedIds.Add(this.Context.ConnectionId);
return base.OnConnected();
}
/// <summary>
/// The on disconnected.
/// </summary>
/// <returns>
/// The <see cref="Task"/>.
/// </returns>
public override Task OnDisconnected()
{
UserHandler.ConnectedIds.Remove(this.Context.ConnectionId);
if (UserHandler.ConnectedIds.Count == 0)
{
try
{
tokenSource.Cancel();
}
catch (Exception ex)
{
Log.Error(ex);
}
}
return base.OnDisconnected();
}
/// <summary>
/// The update tasks status.
/// </summary>
/// <param name="sender">
/// The sender.
/// </param>
/// <param name="e">
/// The e.
/// </param>
public void UpdateTasksStatus(object sender, TaskEventArgs e)
{
this.Clients.All.updateMessages(e.Tasks);
}
#endregion
}
/// <summary>
/// The user handler.
/// </summary>
public static class UserHandler
{
#region Static Fields
/// <summary>
/// The connected ids.
/// </summary>
public static HashSet<string> ConnectedIds = new HashSet<string>();
#endregion
}
public bool IsTasksStatusAsyncRunning()
{
if (tasksStatusAsync != null && tasksStatusAsync.Status.Equals(TaskStatus.Running))
{
return true;
}
return false;
}
Moving this line:
tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
...
making it this:
if (UserHandler.ConnectedIds.Count < 2)
{
Trace.WriteLine("GetTasksStatus: Starting new task");
tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
taskRepository.GetTasksStatusAsync(siteId, tasksItem, ct);
// subscribe to event [ listener ]
tasksItem.Changed += this.UpdateTasksStatus;
}
did it for me. thanks

Resources