Mirror of gRPC calls - c#

I want to be able to mirror all gRPC calls for some services to another set of services with same interface, in C#.
I think about writing extension method for GrpcClientFactory.CreateClient, to return class which would do two calls in parallel. Result from mirror is not needed, so I would return result from first call.
Is it best aproach for the task, or it is possible to make it better?

Pretty much what you described, in your case you can make use of IHttpClientFactory for creating http clients
public class GrpResponse
{
public string client { get; set; }
public HttpResponseMessage response { get; set; }
}
private async void ExecuteGrpRequest()
{
var payLoad = new HttpRequestMessage();
var grpTasks = new List<Task<GrpResponse>>
{
SendAsyc("real", payLoad),
SendAsyc("mock", payLoad)
};
var responses = await Task.WhenAll(grpTasks);
}
private async Task<GrpResponse> SendAsyc(string client, HttpRequestMessage message )
{
// IHttpClientFactory is _httpClientFacotry; injected from ctor
var httpClient = _httpClientFacotry.CreateClient(client);
return new GrpResponse
{
client = client,
response = await httpClient.SendAsync(new HttpRequestMessage())
};
}

Related

How can I use a token from a request for other requests after responding to the first request?

I have a scenario where I need to respond to a request that it's been received and send a response (request?) to another endpoint once internal api calls and logic has completed. The flow looks like this:
External request to my endpoint > endpoint responds to request with accepted > endpoint passes the request on internally > internal logic fetches and handles data from DB > internal logic uses data from DB to send a request back to a different endpoint from the same integration as the first call came from.
I have managed to get it to work using Queued Background Tasks to send the request to the correct internal handler with Mediatr. However in order for it to work I need to add the barer token from the request header to the request object and then use that barer token to validate against the internal API's. I'd like to avoid this since I might run into the issue of the token expiring or not being valid for the internal Api etc.
Request object example:
public class ExampleRequest : IRequest, IRequest<ExampleResponse>
{
public string? Token { get; set; } //Added for functioning version, want to get rid
//of it
public CommonData Data { get; set; }
public string RequestId { get; set; }
public string OperationId { get; set; }
public List<string> ObjectIdentifiers { get; set; }
}
public class CommonData
{
public string MessageId { get; set; }
public DateTime Timestamp { get; set; }
}
Response object example (response to the call):
public class ExampleResponseForCall
{
public CommonData Data { get; set; }
public string ResponseStatus { get; set; } //Will be accepted/acknowledged
}
Example response object (for final response)
public class ExampleResponse
{
public CommonData Data{ get; set; }
public string ResponseStatus { get; set; }
public string ErrorCode { get; set; }
public string ErrorDescription { get; set; }
public string RequestId { get; set; }
public string OperationId { get; set; }
}
My current working version looks something like this:
**Endpoint:**
public IActionResult Post(ExampleRequest request)
{
var authorization = Request.Headers[HeaderNames.Authorization];
if (AuthenticationHeaderValue.TryParse(authorization, out var headerValue))
{
var scheme = headerValue.Scheme;
var parameter = headerValue.Parameter;
}
var token = headerValue?.Parameter;
request.Token = token; //I added token as a nullable string on the request obj
_backgroundTaskQueue.StartTask(request);
return Ok(new ExampleResponseForCall
{
Data = request.Data,
ResponseStatus = HttpStatusCode.Accepted.ToString()
});
}
**Background Task queue:**
public void StartTask(IRequest request)
{
_logger.LogInformation("Task is starting.");
_request = request;
Task.Run(async () => await AddTaskAsync(), _cancellationToken);
}
private async ValueTask AddTaskAsync()
{
await _taskQueue.QueueBackgroundWorkItemAsync(BuildWorkItem);
}
private async ValueTask BuildWorkItem(CancellationToken token)
{
var guid = Guid.NewGuid().ToString();
_logger.LogInformation("Task {Guid} is starting.", guid);
if (_request == null)
{
_logger.LogWarning("Request for task {Guid} is null.", guid);
return;
}
await _mediator.Send(_request, token);
_logger.LogInformation("Task {Guid} is complete.", guid);
}
I also have Handlers that can handle the request and Clients for sending requests internally and back to the caller. All of that works when awaiting the internal logic to be handled. However when I'm using the background task queue the internal client fails on the when getting the token here
protected async Task<HttpClient> CreateBaseClient()
{
var client = _clientFactory.CreateClient(HttpClientName);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("Accept",
$"application/json");
client.DefaultRequestHeaders.Authorization = new
AuthenticationHeaderValue("Bearer", await GetToken());
return client;
}
public async Task<string> GetToken()
{
if (_httpContextAccessor.HttpContext == null)
throw new Exception("No HttpContext available when trying to
get Token.");
_httpContextAccessor.HttpContext.Items.TryGetValue(Constants.AuthenticationSchemeKey,
out var scheme);
if (scheme?.ToString() == Constants.Bearer)
return GetTokenFromRequest();
throw new MissingAccessTokenException("Unknown authentication type");
}
My workaround (that I want to get away from) looks like this:
protected async Task<HttpClient> CreateBaseClient(string version, string token)
{
var client = _clientFactory.CreateClient(HttpClientName);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("Accept",
$"application/json");
client.DefaultRequestHeaders.Authorization = new
AuthenticationHeaderValue("Bearer", token); //token from requst.Token
return client;
}
I've tried to pass in the a lot of different things to the Background Task queue (and changing the parameter type to match ofc) but nothing works. I want to have the background task queue generic since I'll be implementing this for other end points as well.
That's a lot of text so TL:DR, I respond to a request but need to use the token from the request for other calls after responding.
We decided to go with the working solution provided in the question itself.
Due to how our infrastructure is set up we won't be able to get a refresh token (as suggested by #GHDevOps and #TheWallrus) since we won't be able to get the login/id and password/secret of the user in a safe and reasonable way.
However, the working solution in the question has some drawback which should be analyzed on a case-to-case basis. We know that the Api sending us the requests will fetch a new (relevant) token approximately 10 minutes before the current (relevant) token expires and use the new token for all coming requests. Since the logic we apply before passing on the request to our backend is very simple (just simple remapping) we should rarely run into issues with the token expiring before the request has been sent, and in the rare cases that is has, we will send that information in the request back to the external Api, giving them a chance to resend the original request. If the external Api isn't fetching a new token before the expiration of the current token that might cause the token to expire before reaching the internal Api more often which might be a good thing to look after if you're implementing a similar solution.
The code changes that I made for this to function are just minor refactoring (see below). Hope this help anyone else running into a similar issue!
//Endpoint
public IActionResult Post(ExampleRequest request)//Before
{
var authorization = Request.Headers[HeaderNames.Authorization];
if (AuthenticationHeaderValue.TryParse(authorization, out var headerValue))
{
var scheme = headerValue.Scheme;
var parameter = headerValue.Parameter;
}
var token = headerValue?.Parameter;
request.Token = token; //I added token as a nullable string on the request obj
_backgroundTaskQueue.StartTask(request);
return Ok(new ExampleResponseForCall
{
Data = request.Data,
ResponseStatus = HttpStatusCode.Accepted.ToString()
});
}
public IActionResult Post(ExampleRequest request)
{
request.Token = GetToken(Request);//Made into a separate function in the inherited class
_backgroundTaskQueue.StartTask(request);
return Ok(new ExampleResponseForCall
{
Data = request.Data,
ResponseStatus = HttpStatusCode.Accepted.ToString()
});
}
protected string GetToken(HttpRequest request)
{
var authorization = request.Headers[HeaderNames.Authorization];
_ = AuthenticationHeaderValue.TryParse(authorization, out var headerValue);
if (headerValue == null)
{
return "";
}
return string.Equals(headerValue.Scheme, "Bearer", StringComparison.InvariantCultureIgnoreCase) ?
headerValue.Parameter : "";
}
//Client
protected async Task<HttpClient> CreateBaseClient()//before
{
var client = _clientFactory.CreateClient(HttpClientName);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("Accept",
$"application/json");
client.DefaultRequestHeaders.Authorization = new
AuthenticationHeaderValue("Bearer", await GetToken());
return client;
}
protected async Task<HttpClient> CreateBaseClient(string token = "")
{
var client = _clientFactory.CreateClient(HttpClientName);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("Accept", $"application/json");
client.DefaultRequestHeaders.Authorization = new
AuthenticationHeaderValue("Bearer", string.IsNullOrEmpty(token) ?
await GetToken() : token); //We will only send in a token if we are async
return client;
}

How to mock / unit test HTTP Client - restease

tl;dr: I'm having trouble mocking restease**
Also, I realize I may be totally on the wrong track, so any suggestions / nudges in the right direction would be of great help. I am quite new to this.
I'm making a small HTTP Client library, built around RestEase. RestEase is nice and easy to use, but I'm having trouble mocking the calls for the purpose of unit testing.
I want to use moq and NUnit, but I can't properly mock the RestClient. Example (shortened for brevity):
IBrandFolderApi - interface needed by restease to send calls
public interface IBrandFolderApi
{
[Post("services/apilogin")]
Task<LoginResponse> Login([Query] string username, [Query] string password);
}
BrandfolderClient.cs - the main class
public class BrandfolderClient : IBrandfolderClient
{
private IBrandFolderApi _brandFolderApi { get; set; }
public BrandfolderClient(string url)
{
_brandFolderApi = RestClient.For<IBrandFolderApi >(url);
}
public async Task<string> Login(string username, string password)
{
LoginResponse loginResponse = await _brandFolderApi .Login(username, password);
if (loginResponse.LoginSuccess)
{
....
}
....
return loginResponse.LoginSuccess.ToString();
}
}
The unit tests
public class BrandFolderTests
{
BrandfolderClient _brandfolderClient
Mock<IBrandFolderApi> _mockBrandFolderApii;
[SetUp]
public void Setup()
{
//The test will fail here, as I'm passing a real URL and it will try and contact it.
//If I try and send any string, I receive an Invalid URL Format exception.
string url = "https://brandfolder.companyname.io";
_brandfolderClient = new BrandfolderClient (url);
_mockBrandFolderApii= new Mock<IBrandFolderApi>();
}
....
}
So, I don't know how to properly mock the Restclient so it doesn't send an actual request to an actual URL.
The test is failing at the constructor - if I send a valid URL string, then it will send a call to the actual URL. If I send any other string, I get an invalid URL format exception.
I believe I haven't properly implemented something around the rest client, but I'm not sure where. I'm very stuck on this, I've been googling and reading like crazy, but I'm missing something and I don't know what.
So, I don't know how to properly mock the Restclient so it doesn't send an actual request to an actual URL.
You actually should not have any need to mock RestClient.
Refactor your code to depend explicitly on the abstraction you control
public class BrandfolderClient : IBrandfolderClient {
private readonly IBrandFolderApi brandFolderApi;
public BrandfolderClient(IBrandFolderApi brandFolderApi) {
this.brandFolderApi = brandFolderApi; //RestClient.For<IBrandFolderApi >(url);
}
public async Task<string> Login(string username, string password) {
LoginResponse loginResponse = await brandFolderApi.Login(username, password);
if (loginResponse.LoginSuccess) {
//....
}
//....
return loginResponse.LoginSuccess.ToString();
}
}
removing the tight coupling to static 3rd party implementation concerns will allow your subject to be more explicit about what it actually needs to perform its function.
This will also make it easier for the subject to be tested in isolation.
For example:
public class BrandFolderTests {
BrandfolderClient subject;
Mock<IBrandFolderApi> mockBrandFolderApi;
[SetUp]
public void Setup() {
mockBrandFolderApi = new Mock<IBrandFolderApi>();
subject = new BrandfolderClient(mockBrandFolderApi.Object);
}
//....
[Test]
public async Task LoginTest() {
//Arrange
LoginResponse loginResponse = new LoginResponse() {
//...
};
mockBrandFolderApi
.Setup(x => x.Login(It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(loginResponse);
//Act
string response = await subject.Login("username", "password");
//Assert
mockBrandFolderApi.Verify(x => x.Login(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
}
}
In production code, register and configure the IBrandFolderApi abstraction with the container, applying what ever 3rd party dependencies are required
Startup.ConfigureServices
//...
ApiOptions apiOptions = Configuration.GetSection("ApiSettings").Get<ApiOptions>();
services.AddSingleton(apiOptions);
services.AddScoped<IBrandFolderApi>(sp => {
ApiOptions options = sp.GetService<ApiOptions>();
string url = options.Url;
return RestClient.For<IBrandFolderApi>(url);
});
Where ApiOptions is used to store settings
public class ApiOptions {
public string Url {get; set;}
//... any other API specific settings
}
that can be defined in appsetting.json
{
....
"ApiSettings": {
"Url": "https://brandfolder.companyname.io"
}
}
so that they are not hard coded all over you code.
The HttpClient comes from System.Net.Http, which is not easy to mock.
You can, however, create a test HttpClient by passing a fake HttpMessageHandler. Here is an example:
public class FakeHttpMessageHandler : HttpMessageHandler
{
private readonly bool _isSuccessResponse;
public FakeHttpMessageHandler(bool isSuccessResponse = true)
{
_isSuccessResponse = isSuccessResponse;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return Task.FromResult(
new HttpResponseMessage(_isSuccessResponse ? HttpStatusCode.OK : HttpStatusCode.InternalServerError));
}
}
You can create create a test instance of HttpClient as shown below:
var httpClient = new HttpClient(new FakeHttpMessageHandler(true))
{ BaseAddress = new Uri("baseUrl") };
Not sure how you are using verify on _httpClient, its not a mock. but what you are looking for is https://github.com/canton7/RestEase#custom-httpclient. Most people pass in factory for this
//constructor
public httpClientConstructor(string url, IHttpHandlerFactory httpHandler)
{
var httpClient = new HttpClient(httpHandler.GetHandler())
{
BaseAddress = new Uri(url),
};
_exampleApi = RestClient.For<IExampleApi>(url);
}
public interface IHttpHandlerFactory<T>
{
T GetHandler() where T: HttpMessageHandler
}
Thanks Ankit Vijay https://stackoverflow.com/a/68240316/5963888
public class FakeHttpMessageHandler : HttpMessageHandler
{
private readonly bool _isSuccessResponse;
public FakeHttpMessageHandler(bool isSuccessResponse = true)
{
_isSuccessResponse = isSuccessResponse;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return Task.FromResult(
new HttpResponseMessage(_isSuccessResponse ? HttpStatusCode.OK : HttpStatusCode.InternalServerError));
}
}
[SetUp]
public void Setup()
{
var fakeHandler = new Mock<IHttpHandlerFactory>();
fakeHandler.Setup(e => e.GetHandler() ).Returns( new FakeHttpHandler() );
_httpClient = new HttpClient(fakeHandler.Object);
_exampleApi = new Mock<IExampleApi>();
}

Set a default header to each http client call

I want to set a default header for every method in the UserHttpClient but I don`t want that every method is doing that, I want to do it in a general way.
The problem I see with the current implementation is, that when I call one method the _client gets disposed thus at the next call within a Http Request the _client is not initialized, as this happens within the constructor.
The UserHttpClient is registered via DI as per Http Request.
I also do not want to create a private/base method where I pass the _client and do the header addition there.
How would you solve that problem?
public class UserHttpClient : IUserRemoteRepository
{
private readonly string baseUrl = ConfigurationManager.AppSettings["baseUrl"];
private readonly string header = ConfigurationManager.AppSettings["userHeader"];
private readonly HttpClient _client;
public ServiceProductDataProvider(string toolSystemKeyHeader)
{
_client = new HttpClient();
_client.DefaultRequestHeaders.Add(header, token);
}
public async Task<List<UserDto>> GetUsers(UserRequestDto dto)
{
using (_client)
{
// do stuff
var users = await _client.GetAsync("url here");
}
}
public async Task<UserDto> GetUser(Guid userId)
{
using (_client)
{
// do stuff
var users = await _client.GetAsync("url here");
}
}
}
The class UserHttpClient has a member that is IDisposable (private readonly HttpClient _client;). That means that the UserHttpClient should also implement IDisposable:
public void Dispose()
{
_client.Dispose();
}
Then, the class/code that is using UserHttpClient is responsible for Disposing it after it's done with it. If the instance is injected, then the DI framework you use probably handles disposing it automatically at the end of the request. What's left for you then is to simply remove the using blocks from the implementation:
public async Task<List<UserDto>> GetUsers(UserRequestDto dto)
{
// do stuff
var users = await _client.GetAsync("url here");
}
---- EDIT ----
You could also work around the issue by not reusing the HttpClient:
private string _toolSystemKeyHeader;
public ServiceProductDataProvider(string toolSystemKeyHeader)
{
_toolSystemKeyHeader = toolSystemKeyHeader
}
private HttpClient GetClientInstance()
{
HttpClient _client = new HttpClient();
_client.DefaultRequestHeaders.Add(header, _toolSystemKeyHeader); //?? in your original code, the toolSystemKeyHeader is not used, but I guess it is the token..?
return _client;
}
And:
public async Task<List<UserDto>> GetUsers(UserRequestDto dto)
{
using (var _client = GetClientInstance())
{
// do stuff
var users = await _client.GetAsync("url here");
}
}

Async is becoming a pain in the behind because I'm trying to make a re-usable library that doesn't suck

Because Post requests to APIs need to run asynchronously on windows phone, I am struggling to create a lean easy to use library to interact with an API.
The issue is that people using the library will always need to supply a callback function.
Let's take a look at some pseudo code:
PostRequest Class to help me with POST requests:
class PostRequest
{
private Action<MemoryStream> Callback;
public PostRequest(string urlPath, string data, Action<MemoryStream> callback)
{
Callback = callback;
// Form the URI
UriBuilder fullUri = new UriBuilder(urlPath);
if (!string.IsNullOrEmpty(data))
fullUri.Query = data;
// Initialize a new WebRequest
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(fullUri.Uri);
request.Method = "POST";
// Set up the state object for the async request
DataUpdateState dataState = new DataUpdateState();
dataState.AsyncRequest = request;
// Start the asynchronous request
request.BeginGetResponse(new AsyncCallback(HandleResponse),
dataState);
}
private void HandleResponse(IAsyncResult asyncResult)
{
// Get the state information
DataUpdateState dataState = (DataUpdateState)asyncResult.AsyncState;
HttpWebRequest dataRequest = (HttpWebRequest)dataState.AsyncRequest;
// End the async request
dataState.AsyncResponse = (HttpWebResponse)dataRequest.EndGetResponse(asyncResult);
if (dataState.AsyncResponse.StatusCode.ToString() == "OK")
{
// Create a stream from the response
Stream response = dataState.AsyncResponse.GetResponseStream();
TextReader textReader = new StreamReader(response, true);
string jsonString = textReader.ReadToEnd();
MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
// Send the stream through to the callback function
Callback(stream);
}
}
}
public class DataUpdateState
{
public HttpWebRequest AsyncRequest { get; set; }
public HttpWebResponse AsyncResponse { get; set; }
}
The API Access Object classes:
class APIAuthenticationCredentials
{
public String Username { get; set; }
public String Password { get; set; }
}
class APIAO
{
private String AuthUrl = "http://api.example.com/";
public static Auth Auth = new Auth();
//...
public static void Authenticate( String data, APIAuthenticationCredentials credentials, Action<MemoryStream> callback )
{
PostRequest request = new PostRequest(AuthURL, data, callback);
}
//...
}
You will notice I have to pass a callback function all the way through this so that once the data is returned by the HandleResponse method in my PostRequest class, the data is forwarded onto some controller that makes the screen do something with the data. At the moment, it's not ultra horrid to use:
private void DisplayData(MemoryStream stream)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Auth));
APIAO.Auth = (Auth)serializer.ReadObject(stream);
}
//...
APIAuthenticationCredentials credentials = new APIAuthenticationCredentials {
Username = "whatever",
Password = "whatever"
}
APIAO.Authenticate( credentials, DisplayData );
//...
The problem is I want to create some kind of repository style pattern... Let's say the API returned different json models, one call returned an array of products... the problem is that I want to create one lovely repository call eg:
IProductRepository productRepository = new ProductRepository();
productRepository.GetAll();
But I've gotta put some GOSH DARN callback function in it too and that means every repository method of any object type returned by the API is going to have this MemoryStream callback... and if I ever want to change that functionality, I've gotta update that stuff everywhere yo. :(
Has anyone seen a better way of doing this crap.
This is starting to become far too complex
--crying
A simpler answer using newer language constructs would be:
public static Task<string> GetData(string url, string data)
{
UriBuilder fullUri = new UriBuilder(url);
if (!string.IsNullOrEmpty(data))
fullUri.Query = data;
WebClient client = new WebClient();
client.Credentials = CredentialCache.DefaultCredentials;//TODO update as needed
return client.DownloadStringTaskAsync(fullUri.Uri);
}
In a 4.0 project you can use a TaskCompletionSource to translate a non-Task asynchronous model into a Task:
public static Task<string> GetData2(string url, string data)
{
UriBuilder fullUri = new UriBuilder(url);
if (!string.IsNullOrEmpty(data))
fullUri.Query = data;
WebClient client = new WebClient();
client.Credentials = CredentialCache.DefaultCredentials;//TODO update as needed
var tcs = new TaskCompletionSource<string>();
client.DownloadStringCompleted += (s, args) =>
{
if (args.Error != null)
tcs.TrySetException(args.Error);
else if (args.Cancelled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(args.Result);
};
client.DownloadStringAsync(fullUri.Uri);
return tcs.Task;
}
The caller now has a Task<string> that represents the results of this asynchronous operation. They can wait on it synchronously and get the result using the Result property, they can add a callback that will execute when the operation finishes using ContinueWith, or they can await the task in an async method which, under the hood, will wire up the remainder of that method as a continuation of that task, but without creating a new method or even a new scope, i.e.
public static async Task Foo()
{
string result = await GetData("http://google.com", "");
Console.WriteLine(result);
}
This will start the asynchronous task, add a callback (or continuation) to that task so that when it runs it will continue executing code where it left off, at which point it will then write the results to the console and mark the Task that this method returns as completed, so that any continuations to this method will then execute (allowing for composition of async methods).

HttpClient await hangs on PostAsync with async void method

I'm still trying to wrap my head around async and I'm wondering why the following code is causing a deadlock. My use case is this: I have a service interface which attempts to abstract how the service is implemented. One of the services is an OAuth based web-service. The service interface has a method Connect() which anyone using the interface must do prior to using it.
On my client side I create my concrete service object and call Connect() in my view constructor (this is a prototype, so I'm just trying to get a proof of concept going). In the OAuth-based service, the connect call requires retrieving an access token, so it (attempts) to do this asynchronously. This Connect() call never returns, though, and the application is deadlocked (but the UI is active). I'm guessing I'm messing up and trying to synchronously use my client somewhere, but I'm not sure where.
Control
public class MainWindow
{
public MainWindow()
{
InitializeComponent();
_webService = new OAuthBasedWebService();
_webService.ShowAuthorizationPage += _webService_ShowAuthorizationPage; // this is defined on the concrete object -- i know, bad design
_webService.Connect();
}
}
OAuth based webservice
public class OAuthBasedWebService()
{
private OAuthWrapper _wrapper;
public async void Connect()
{
var uri = await _wrapper.GetAuthorizationUri();
OnShowAuthorizationPage(uri);
}
}
internal class OAuthWrapper
{
public async Task<Uri> GetAuthorizationUri()
{
var uri = await _consumer.GetAuthorizationUriAsync();
return uri;
}
}
internal class OAuthConsumer
{
public async Task<Uri> GetAuthorizationUriAsync()
{
using (var client = new HttpClient())
{
client.BaseAddress = "webservicebaseaddress";
var content = new FormUrlEncodedContent(new []
{
CreateParameter("oauth_consumer_key", "consumerkey"),
CreateParameter("oauth_consumer_secret", "consumersecret")
// etc., etc.
});
var response = await client.PostAsync("/method_path", content).ConfigureAwait(false);
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
// parse authorization uri from responseContent
return authorizationUri;
}
}
}
I know the design needs a little work but I'm trying to figure out why this is deadlocking. I'm guessing it is because _webService.Connect() is not being called asynchronously but I also cannot await that because it doesn't return anything and the rest of the program doesn't depend on it.
I'm not sure why you are using a event here, if the problem was just because you couldn't make the constructor "async" then just move the conect call to another method:
public class MainWindow
{
public MainWindow()
{
InitializeComponent();
Init();
}
public async void Init(){
_webService = new OAuthBasedWebService();
Uri uri=await _webService.Connect();
_webService_ShowAuthorizationPage(uri);
}
}
public class OAuthBasedWebService()
{
private OAuthWrapper _wrapper;
public async Task<Uri> Connect()
{
return await _wrapper.GetAuthorizationUri();
}
}

Categories

Resources