I am getting the Cannot access a disposed object. Object name: 'Transaction'.' error message when I try to call sendlocal method.
In the handler, I am making a cosmos DB call to get the required information before calling this sendlocal method.
public async Task Handle(OrderCommand message, IMessageHandlerContext context)
{
//Cosmos DB call to get the required information
var requiredInfo = await cosmosClient.GetInformation(message.Id);
await context.SendLocal(requiredInfo);
}
And below is the service bus configuration sample code
var endpointConfiguration = new EndpointConfiguration(endpointName);
var transport = endpointConfiguration.UseTransport<AzureServiceBusTransport>();
transport.ConnectionString(GetTransportConnectionString(configuration));
//transport.Transactions(TransportTransactionMode.TransactionScope);
endpointConfiguration.UseSerialization<NewtonsoftSerializer>();
endpointConfiguration.UsePersistence<CosmosPersistence>()
.CosmosClient(new CosmosClient(cosmosConnectionString))
.DatabaseName(configuration.GetConnectionString("DATABASENAME"))
.DefaultContainer(containerName: "sagastore", partitionKeyPath: "/id")
.DisableContainerCreation();
endpointConfiguration.SendFailedMessagesTo("error");
endpointConfiguration.AuditProcessedMessagesTo("audit");
endpointConfiguration.AuditSagaStateChanges(serviceControlQueue: "audit");
endpointConfiguration.EnableInstallers();
Related
In one of my Azure Function app(.Net 6 isolated process) and I am making some http requests with a client certificate. I'm registering my services in the Program.cs like this,
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(clientCertificate);
services.AddHttpClient().Configure<HttpClientFactoryOptions>(
"myClient", options =>
options.HttpMessageHandlerBuilderActions.Add(builder =>
builder.PrimaryHandler = handler));
services.AddTransient<IMyCustomClient, MyCustomClient>(provider =>
new MyCustomClient(provider.GetService<IHttpClientFactory>(),
cutomParameter1, cutomParameter2));
services.AddSingleton<IMyCustomService, MyCustomService>();
And injecting MyCustomClient in MyCustomService constructor
private readonly IMyCustomClient _myCustomClient;
public PlatformEventManagementService(IMyCustomClient myCustomClient)
{
_myCustomClient = myCustomClient;
}
var result = await _myCustomClient.GetResponse();
It works fine for some time and getting the below exception after sending many requests.
Cannot access a disposed object. Object name: 'SocketsHttpHandler'.
You are supplying the factory with a single instance of HttpClientHandler to use in all clients. Once the default HandlerLifetime has elapsed (2 minutes) it will be marked for disposal, with the actual disposal occurring after all existing HttpClients referencing it are disposed.
All clients created after the handler is marked continue to be supplied the soon-to-be disposed handler, leaving them in an invalid state once the disposal is actioned.
To fix this, the factory should be configured to create a new handler for each client. You may wish to use the simpler syntax shown in the MS documentation.
// Existing syntax
services.AddHttpClient().Configure<HttpClientFactoryOptions>(
"myClient", options =>
options.HttpMessageHandlerBuilderActions.Add(builder =>
{
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(clientCertificate);
builder.PrimaryHandler = handler;
}));
// MS extension method syntax
services
.AddHttpClient("myClient")
// Lambda could be static if clientCertificate can be retrieved from static scope
.ConfigurePrimaryHttpMessageHandler(_ =>
{
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(clientCertificate);
return handler;
});
AcquireTokenByUsernamePassword throws System.AggregateException and MsalServiceException:
1st Exception:
System.AggregateException: 'One or more errors occurred. (Federated
service at
https://autologon.microsoftazuread-sso.com/domain.com/winauth/trust/2005/usernamemixed?client-request-id=[ID]
returned error: Authentication Failure )'
2nd Exception:
MsalServiceException: Federated service at
https://autologon.microsoftazuread-sso.com/domain.com/winauth/trust/2005/usernamemixed?client-request-id=[ID]
returned error: Authentication Failure
string clientId = "client-id";
string tenant = "tenant-id";
// Open connection
string authority = "https://login.microsoftonline.com/" + tenant;
string[] scopes = new string[] { "user.read" };
IPublicClientApplication app;
app = PublicClientApplicationBuilder.Create(clientId)
.WithAuthority(authority)
.Build();
var securePassword = new SecureString();
foreach (char c in user.Password.ToCharArray()) // you should fetch the password
securePassword.AppendChar(c); // keystroke by keystroke
var results = app.AcquireTokenByUsernamePassword(scopes, user.UserName, securePassword).ExecuteAsync().Result.IdToken;
Your scope is set incorrectly. I think you want to call your custom api instead of ms graph api, so you should get a token for your expose api. The scope you set in the code is the permissions of ms graph api instead of your custom api scope.
Therefore, you need to set the scope to: api://{api app client id}/.default.
I'm buildin a console Web API to communicate with a localhost server, hosting computer games and highscores for them. Every time I run my code, I get this charming error:
fail:
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.NotSupportedException: Deserialization of types without a
parameterless constructor, a singular parameterized constructor, or a
parameterized constructor annotated with 'JsonConstructorAttribute' is
not supported. Type 'System.Net.Http.HttpContent'. Path: $ |
LineNumber: 0 | BytePositionInLine: 1.
This is the method I'm using to post to the database. Note that this method is not in the console application. It is in the ASP.NET Core MvC application opening a web browser and listening for HTTP requests (which can come from the console application).
[HttpPost]
public ActionResult CreateHighscore(HttpContent requestContent)
{
string jasonHs = requestContent.ReadAsStringAsync().Result;
HighscoreDto highscoreDto = JsonConvert.DeserializeObject<HighscoreDto>(jasonHs);
var highscore = new Highscore()
{
Player = highscoreDto.Player,
DayAchieved = highscoreDto.DayAchieved,
Score = highscoreDto.Score,
GameId = highscoreDto.GameId
};
context.Highscores.Add(highscore);
context.SaveChanges();
return NoContent();
}
I'm sending POST requests in a pure C# console application, with information gathered from user input, but the result is exactly the same when using Postman for post requests - the above NotSupportedException.
private static void AddHighscore(Highscore highscore)
{
var jasonHighscore = JsonConvert.SerializeObject(highscore);
Uri uri = new Uri($"{httpClient.BaseAddress}highscores");
HttpContent requestContent = new StringContent(jasonHighscore, Encoding.UTF8, "application/json");
var response = httpClient.PostAsync(uri, requestContent);
if (response.IsCompletedSuccessfully)
{
OutputManager.ShowMessageToUser("Highscore Created");
}
else
{
OutputManager.ShowMessageToUser("Something went wrong");
}
}
I'm new to all this HTTP requests stuff, so if you spot some glaring errors in my code, that would be appreciated. Though, the most important question is, what am I missing, and how can I read from the HttpContent object, to be able to create a Highscore object to send to the database?
It seems to be the string jasonHs... line that is the problem, since the app crashed in exactly the same way, when I commented out the rest of the ActionResult method.
Based on your code, we can find that you make a HTTP Post request with a json string data (serialized from a Highscore object) from your console client to Web API backend.
And in your action method, you create an instance of Highscore manually based on received data, so why not make your action accept a Highscore type parameter, like below. Then the model binding system would help bind data to action parameter(s) automatically.
[HttpPost]
public ActionResult CreateHighscore([FromBody]Highscore highscore)
{
//...
We have an HttpTriggred function according to the following code snippet:
[FunctionName("commandcompleted")]
public static Task SendMessage(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "commandcompleted/{userId}")]
object message,
string userId,
[SignalR(HubName = Negotitate.HubName)]IAsyncCollector<SignalRMessage>
signalRMessages,
ILogger log)
{
return signalRMessages.AddAsync(
new SignalRMessage
{
UserId = userId,
Target = "CommandCompleted",
Arguments = new[] { message }
});
}
The client app which is, in fact, a signalR client receives a notification upon completion an operation once the mentioned trigger is invoked.
It's observed that the payload received by the client app is always in Pascal Case. How can we augment the function's code so that it broadcasts the payload in camel case format? Please note that decorating the object's properties by [JsonProperty("camelCasePropertyName")] is not an option and we'd like to do away from it.
The application tier which prepares message object must take care of serializing it in camel case format before submitting it to the http-triggered function.
I have a web service (made in Asp.net Web API) that returns an xml file of about 10MB size.
The service has been tested with Fiddler and it is working
I am trying to download the file using HttpClient class. The problem is that the compilator never gets outside the await client.GetAsync() method, even if the API project returned the HttpResponseMessage.
This is my function
public async Task<XDocument> DownloadXmlAsync(string xmlFileName)
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:51734/");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/xml"));
// When the copiler enters this next command, it doesn't get outside anymore
HttpResponseMessage response = await client.GetAsync("api/applications/ApplicationXml?fileName=" + xmlFileName);
response.EnsureSuccessStatusCode();
string stringResponse = await response.Content.ReadAsStringAsync();
XDocument xDoc = new XDocument(stringResponse);
return xDoc;
}
}
I updated also the maxRequestLength in web.config
<httpRuntime maxRequestLength="15360" />
What i am doing wrong?
Edit
Calling the function
public async Task<ActionResult> Index()
{
var xmlTask = DownloadXmlAsync("1.xml");
// doesn't reach here
var result = xmlTask.Result;
return View();
}
You're causing a classic deadlock by calling Result. Instead, you should await the task:
public async Task<ActionResult> Index()
{
var xmlTask = DownloadXmlAsync("1.xml");
// doesn't reach here
var result = await xmlTask;
return View();
}
I explain this deadlock in full on my blog, but the general idea is like this:
ASP.NET only allows one thread to be processing a request at a time.
When you await a Task, the compiler will capture a "context" and use it to resume the method when the Task completes. In the case of ASP.NET, this "context" is a request context.
So when DownloadXmlAsync (asynchronously) waits for GetAsync to complete, it returns an incomplete task to Index.
Index synchronously blocks on that task. This means the request thread is blocked until that task completes.
When the file is received, GetAsync completes. However, DownloadXmlAsync cannot continue because it's trying to resume that "context", and the "context" already has a thread in it: the one blocked on the task.
Hence, deadlock.