My working SignalR ASP.NET Core 5 Windows Service with a simple string payload (or even more value type parameters) does not work anymore when I change it to a (simple) complex object ("CommonMessage" in my case). From what I read, it should work out of the box. The "SendCommonMessage" method doesn't get called anymore and I am not getting any error. What am I missing? Is there no way of debugging/getting the error shown? (The ASP.NET Service gets called by a WPF Core 5 application.)
public class CommonMessageHub : Hub
{
public async Task SendCommonMessage(CommonMessage commonMessage)
{
await Clients.All.SendAsync("ReceiveCommonMessage", commonMessage);
}
}
public class CommonMessage
{
public int MessageType { get; set; }
public int Id { get; set; }
public string Text { get; set; }
}
The caller (WPF app) looks like so:
public class CommonMessageService
{
public CommonMessageService(HubConnection connection)
{
_connection = connection;
_connection.On<CommonMessage>("ReceiveCommonMessage", commonMessage => CommonMessageReceived?.Invoke(commonMessage));
}
private readonly HubConnection _connection;
public event Action<CommonMessage> CommonMessageReceived;
public async Task Connect()
{
await _connection.StartAsync();
}
public async Task SendCommonMessage(CommonMessage commonMessage)
{
await _connection.SendAsync("SendCommonMessage", commonMessage);
}
}
Related
I'm very new to ASP.NET Web API and I'm trying to use Entity Framework Core's Dependency Injection to POST data to the API Controller using MediatR pattern. But every time I run my code and it opens Swagger UI, I get an error 500 response saying
Unable to cast object of type 'AsyncStateMachineBox1[System.Threading.Tasks.VoidTaskResult,S3E1.Repository.CartItemRepository+<Createitem>d__5]' to type 'System.Threading.Tasks.Task1[S3E1.Entities.CartItemEntity]'.
First, I added Dependency Injections to Program.cs
//Dependency Injection
builder.Services.AddDbContext<AppDataContext>(contextOptions => contextOptions.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection")
));
//Connection
builder.Services.AddSingleton<DataConnectionContext>();
These are the classes.
AppDataContext.cs
public class AppDataContext : DbContext
{
public AppDataContext(DbContextOptions<AppDataContext> contextOptions) : base(contextOptions) { }
public DbSet<CartItemEntity> CartItems { get; set; }
public DbSet<OrderEntity> Orders { get; set; }
public DbSet<UserEntity> Users{ get; set; }
}
DataConnectionContext.cs
public class DataConnectionContext
{
private readonly IConfiguration _configuration;
private readonly string _connectionString;
public DataConnectionContext(IConfiguration configuration)
{
_configuration = configuration;
_connectionString = _configuration.GetConnectionString("DefaultConnection");
}
public IDbConnection CreateConnection() => new SqlConnection(_connectionString);
}
Next is making a repository which holds the interface that has the create method.
public interface ICartItemRepository
{
//public Task<IEnumerable<CartItemEntity>> GetCartItems();
//public Task<CartItemEntity> GetCartItemEntity(Guid id);
public Task Createitem(CartItemEntity itemEntity);
}
Then a class that inherits the interface and calls the dependency constructors
public class CartItemRepository : ICartItemRepository
{
private readonly DataConnectionContext _connectionContext;
private readonly AppDataContext _appDataContext;
public CartItemRepository(DataConnectionContext connectionContext, AppDataContext appDataContext)
{
_connectionContext = connectionContext;
_appDataContext = appDataContext;
}
public async Task Createitem(CartItemEntity itemEntity)
{
_appDataContext.CartItems.Add(itemEntity);
await _appDataContext.SaveChangesAsync();
await _appDataContext.CartItems.ToListAsync();
}
}
Next is a command for POST request MediatR pattern
public record AddCartItemCommand(CartItemEntity cartItem) : IRequest<CartItemEntity>;
and a Handler which manages and returns the method createitem
public class AddItemsHandler : IRequestHandler<AddCartItemCommand, CartItemEntity>
{
private readonly ICartItemRepository _cartItemRepository;
public AddItemsHandler(ICartItemRepository cartItemRepository) => _cartItemRepository = cartItemRepository;
public async Task<CartItemEntity> Handle(AddCartItemCommand request, CancellationToken cancellationToken)
{
return await (Task<CartItemEntity>) _cartItemRepository.Createitem(request.cartItem);
}
}
and lastly, in the controller
[Route("api/cart-items")]
[ApiController]
public class CartItemsController : ControllerBase
{
private ISender _sender;
public CartItemsController(ISender sender) => _sender = sender;
[HttpPost]
public async Task<CartItemEntity> Post(CartItemEntity cartItemEntity)
{
return await _sender.Send(new AddCartItemCommand(cartItemEntity));
}
}
I tried modifying the return object in the handler but every time I change anything it always get the error squiggly line, so I just casted the (Task) after the await. Is this where I went wrong? Thank you for any answers.
The exception is clear. You can't cast a VoidTaskResult to Task<CartItemEntity>.
To solve the problem:
In ICartItemRepository, modify the return type for Createitem as Task<CartItemEntity>.
In CartItemRepository, implement Createitem method from the ICartItemRepository interface. Return the inserted itemEntity in the method.
Since you have implemented Task<CartItemEntity> Createitem(CartItemEntity itemEntity) in the ICartItemRepository interface, the casting to (Task<CartItemEntity>) is no longer needed, and suggested to be removed.
public interface ICartItemRepository
{
...
public Task<CartItemEntity> Createitem(CartItemEntity itemEntity);
}
public class CartItemRepository : ICartItemRepository
{
...
public async Task<CartItemEntity> Createitem(CartItemEntity itemEntity)
{
_appDataContext.CartItems.Add(itemEntity);
await _appDataContext.SaveChangesAsync();
return itemEntity;
}
}
public class AddItemsHandler : IRequestHandler<AddCartItemCommand, CartItemEntity>
{
...
public async Task<CartItemEntity> Handle(AddCartItemCommand request, CancellationToken cancellationToken)
{
return await _cartItemRepository.Createitem(request.cartItem);
}
}
I'm learning AWS Lambda with C#. My function looks sort of like this:
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace Function_Redeem
{
public class Function
{
public FunctionOutput FunctionHandler(FunctionInput input, ILambdaContext context)
{
// do work with input
// return FunctionOutput
}
public class FunctionInput
{
public string someData { get; set; }
}
public class FunctionOutput
{
public string someAnswer { get; set; }
}
}
}
It works fine when using the Test button in AWS, as well as the test feature in Visual Studio.
Now, I'm trying to call this from Unity.
So first, I added an API Gateway trigger, and left the defaults:
API endpoint: [the url]
API type: HTTP
Authorization: NONE
Cross-origin resource sharing (CORS): No
Enable detailed metrics: No
Method: ANY
Resource path: /FunctionName
Stage: default
Then in Unity,
private static IEnumerator TestFunction(string uri, string data)
{
UnityWebRequest webRequest = UnityWebRequest.Put(uri, data);
yield return webRequest.SendWebRequest();
if (webRequest.isNetworkError)
Debug.LogError("Network error: " + webRequest.error);
else
Debug.Log(webRequest.downloadHandler.text);
}
I call it, with data being
{"someData":"Hello"}
The function call works, I know that it is reaching my function, but the input data (i.e. the someData field) is null. It seems like it's not parsing the data I'm sending so FunctionInput defaults to null someData.
What am I missing?
Since you are using API Gateway as a trigger to your lambda function, accept APIGatewayProxyRequest as input parameter to your handler(instead of FunctionInput). The field Body would have your serialized payload {"someData":"Hello"}
public class Function
{
public FunctionOutput FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
{ var requestBody = JsonConvert.DeserializeObject<FunctionInput>(request.Body);
// do work with input
// return FunctionOutput
}
public class FunctionInput
{
public string someData { get; set; }
}
public class FunctionOutput
{
public string someAnswer { get; set; }
}
}
}
I have a long-running process: IHostedService. It runs all day long calling different external apis (services) to pull in data. I would like to get notified if during this process any of these external services failed/exceptions got thrown, the process is taking longer than 30 min etc. How would I set it up?
After some research, I ended up with this:
https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-5.0#separate-readiness-and-liveness-probes (StartupHostedServiceHealthCheck section)
How do I implement .NET Core Health Checks on a Hosted Service?
This is what I have so far:
// Registered as Singleton
public interface IHostedServiceStatus
{
bool IsHostedServiceRunning { get; set; }
DateTime RunTime { get; }
string Message { get; }
void Setup(string name, DateTime runTime, string message = null);
}
public class HostedServiceStatus : IHostedServiceStatus
{
private string _message;
private string _name;
public string Message => $"HostedService {_name} started on: {RunTime} failed to complete. {_message}";
public bool IsHostedServiceRunning { get; set; }
public DateTime RunTime { get; private set; }
public void Setup(string name, DateTime runTime, string message = null)
{
_name = name;
RunTime = runTime;
IsHostedServiceRunning = true;
if (!string.IsNullOrEmpty(message))
_message = message;
}
}
// HealthCheck
public class HostedServiceHealthCheck : IHealthCheck
{
private readonly IHostedServiceStatus _hostedServiceStatus;
private readonly TimeSpan _duration = TimeSpan.FromMinutes(30);
public HostedServiceHealthCheck(IHostedServiceStatus hostedServiceStatus)
{
_hostedServiceStatus = hostedServiceStatus;
}
public Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default)
{
if (_hostedServiceStatus.IsHostedServiceRunning)
{
if (_hostedServiceStatus.RunTime.Subtract(DateTime.Now).Duration() >= _duration)
return Task.FromResult(
HealthCheckResult.Unhealthy(_hostedServiceStatus.Message));
}
return Task.FromResult(
HealthCheckResult.Healthy("Task is finished."));
}
}
// Long running process
public async void Process(object state)
{
// each service runs about 10 min
foreach (var externalService in externalServices)
{
try
{
_hostedServiceStatus.Setup(externalService.Name, DateTime.Now); // setup healthcheckStatus - injected
...
// calls externalService gets data and saves to db
_dataMinerStatus.IsHostedServiceRunning = false; // udpate Healthcheck - finished successfully
}
catch (Exception ex)
{
// set MInDateTime so that it becamse UnHealthy
_hostedServiceStatus.Setup(externalService.Name, DateTime.MinValue);
// HealthCheck injected
await _healthCheck.CheckHealthAsync(new HealthCheckContext()); // send notification? (webhook setup) - will this work?
}
}
I have a simple hosted service(called TransactionService) in a .net core web api app.
I'm having issues with populating a List in the TransactionService
In my TransactionController I'm using the following method to add a transaction:
public IActionResult CreateTransaction(Transaction transaction)
{
// validate
var _transactionS= (TransactionService)_transactionService.Service;
_transactionS.Add(transaction);
return Ok();
}
And in my TransactionService class:
private List<Transaction> transactions = new List<Transaction>();
public void AddTransaction(Transaction transaction)
{
transactions.Add(transaction);
}
protected override Task FilterTransactions()
{
foreach(var item in transactions)
{
//Do some work
}
return Task.CompletedTask;
}
}
So when I call CreateTransaction in my controller this will call the AddTransaction method in my service class.
The FilterTransaction method gets executed every 5 seconds, go through every element of my list and check some conditions, only problem is that my transactions list is empty.
If I add a breakpoint in my AddTransactionMethod it will show me the correct count, but a breakpoint on my foreach statement will show count 0.
This is the Startup class code to register the service
services.AddHostedService<TransactionService>();
services.AddSingleton<IHostedServiceAccessor<ITransactionService>, HostedServiceAccessor<ITransactionService>>();
And the TransactionService setup:
public interface IHostedServiceAccessor<out T> where T : IHostedService
{
T Service { get; }
}
public class HostedServiceAccessor<T> : IHostedServiceAccessor<T> where T : IHostedService
{
public HostedServiceAccessor(IEnumerable<IHostedService> hostedServices)
{
Service = hostedServices.OfType<T>().FirstOrDefault();
}
public T Service { get; }
}
public interface ITransactionService: IHostedService
{
}
internal class TransactionService : TransactionServiceBase, ITransactionService
{
private List<Transaction> transactions = new List<Transaction>();
public TransactionService()
:base(TimeSpan.FromMilliseconds(5000))
{
}
public void AddTransaction(Transaction transaction)
{
transactions.Add(transaction);
}
protected override Task FilterTransactions()
{
foreach (var item in transactions)
{
//Do some work
}
return Task.CompletedTask;
}
}
The TransactionServiceBase class is inheriting form BackgroundService and is a DLL. It has an abstract FilterTransaction method and another one sealed ExecuteAsync()
This question already has answers here:
Dependency Injection wcf
(2 answers)
Closed 6 years ago.
In developing a WPF application that allows editing of article and carrier (pallet, racking) data (in a CRUD-fashion) I'm looking how to manage the lifecycle of the WCF clients connecting to the service that contains the actual data.
I prefer to use an MVVM approach using Caliburn Micro and StructureMap or Castle Windsor.
My main issue is not the creation of WCF client channels or factories, but more important the cleanup after use. I intend to use per-request lifecycle on the server side, as such I will need to create and dispose my clients on a per-request basis. As such I have the following in mind:
public class Article
{
public int Id { get; set; }
public string ArticleId { get; set; }
}
[ServiceContract]
public interface IArticleCrud
{
[OperationContract]
Article CreateArticle(string articleId);
[OperationContract]
void Delete(int articleId);
}
public class ArticlesViewModel
{
private readonly Func<IArticleCrud> articleCrudFactory;
public ArticlesViewModel(Func<IArticleCrud> articleCrudFactory)
{
this.articleCrudFactory = articleCrudFactory;
}
public void Delete(int articleId)
{
// Doesn't work since IArticleCrud is not IDisposable
using (var crud = articleCrudFactory())
{
crud.Delete(articleId);
}
}
}
As noted in the comment this won't work because IArticleCrud is not IDisposable. IArticleCrud is used to create a ChannelFactory on the client side to generate proxies for the service implementing the same interface. I'd happily swap out this code for the following:
public class DeleteArticleCommand : IRequest
{
public int Id { get; set; }
}
public class ArticlesViewModel
{
private readonly IMediator mediator;
public ArticlesViewModel(IMediator mediator)
{
this.mediator = mediator;
}
public void Delete(int articleId)
{
mediator.Send(new DeleteArticleCommand {Id = articleId});
}
}
public class DeleteArticleCommandHandler : RequestHandler<DeleteArticleCommand>
{
private readonly IArticleCrud articleCrud;
public DeleteArticleCommandHandler(IArticleCrud articleCrud)
{
this.articleCrud = articleCrud;
}
protected override void HandleCore(DeleteArticleCommand message)
{
articleCrud.Delete(message.Id);
}
}
However, this doesn't solve my problem as I'm still not dealing with the disposal of the WCF client. I could however make the IMediator create a new nested container on the Send action and have it disposed after the Send action completes, but it seems like a lot of hassle.
Am I getting it all wrong, or does it just require a lot of effort just to perform a WCF call from a WPF application?
As a sidenote, I will be having more services than just these few CRUD services, so the perhaps pragmatic solution of fixing this in my CRUD services is not an option.
I've dealt with the same Problem (WCF-Service used in a WPF Application) and wanted to use the ServiceInterface instead the ServiceClient (which is IDisposable and can be used in a using-block).
One of the solutions to Close the Connection is to cast the Interface to the Client-type and call the .Close()-Method:
public class Article
{
public int Id { get; set; }
public string ArticleId { get; set; }
}
public interface IArticleCrud
{
Article CreateArticle(string articleId);
void Delete(int articleId);
}
public class ArticlesViewModel
{
private readonly Func<IArticleCrud> articleCrudFactory;
public ArticlesViewModel(Func<IArticleCrud> articleCrudFactory)
{
this.articleCrudFactory = articleCrudFactory;
}
public void Delete(int articleId)
{
//Using-Block doesn't work since IArticleCrud is not IDisposable
var crud = articleCrudFactory();
crud.Delete(articleId);
if (crud is ArticleCrud)
(crud as ArticleCrud).Close();
}
}
You can also create a static method in your articleCrudFactory that will Close your IArticleCrud:
public static void CloseInterface(IArticleCrud crud)
{
if (crud is ArticleCrud)
(crud as ArticleCrud).Close();
else { ... }
}
I've done it already with WCF and MVVM and its really easy (if I get your problem right):
public interface IRequest
{
}
public interface IRequestHandler<in TCommand> where TCommand : IRequest
{
void HandleCore(TCommand command);
}
public class DeleteArticleCommand : IRequest
{
public int Id { get; set; }
}
public class ArticlesViewModel
{
private readonly IRequestHandler<DeleteArticleCommand> _handler;
public ArticlesViewModel(IRequestHandler<DeleteArticleCommand> handler)
{
_handler = handler;
}
public void Delete(int articleId)
{
_handler.HandleCore(new DeleteArticleCommand { Id = articleId });
}
}
//On client side
public sealed class WcfServiceCommandHandlerProxy<TCommand>
: IRequestHandler<TCommand> where TCommand : IRequest
{
public void HandleCore(TCommand command)
{
using (var service = new ActuaclWcfServiceClient())
{
service.Send(command); //Or however you are working with you WCF client
}
}
}
//Somewhere on server side
public class DeleteArticleCommandHandler : IRequestHandler<DeleteArticleCommand>
{
private readonly IArticleCrud _articleCrud;
public DeleteArticleCommandHandler(IArticleCrud articleCrud)
{
_articleCrud = articleCrud;
}
public void HandleCore(DeleteArticleCommand message)
{
articleCrud.Delete(message.Id);
}
}
Just register your IRequestHandler interface to be implemented with WcfServiceCommandHandlerProxy type and that's it:
//May vary :)
Register(typeof (ICommandHandler<>), typeof (WcfServiceCommandHandlerProxy<>))