The error occurs only with ReverseProxy Server. With Normal Server everything is fine. ReverseProxy Server creates proxied Instances of services and injects them in the controller. In the proxied service I got the error:
Unable to cast object of type 'd__1[NotificationMarkResultDto]' to type 'System.Collections.Generic.IReadOnlyCollection`1[NotificationMarkResultDto]'.
When I debug the Reverse Proxy Server, go to the controller, then I can see the contents of the injected service in which an error occurs:
debug screenshot Injected NotificationService
These are methods where proxy services are created.
public INotificationService GetNotificationService()
{
return _host.Get<INotificationService>(INotificationService.NetServiceId, NetServiceFactory.Instance);
}
private sealed class NetServiceFactory : INetServiceFactory
{
public static readonly INetServiceFactory Instance = new NetServiceFactory();
/// <inheritdoc />
public string ResolveServiceAddress(string serviceKey)
{
throw new NotSupportedException();
}
/// <inheritdoc />
public TServiceContract CreateProxy<TServiceContract>(INetServiceProxy netServiceProxy)
{
return NetServiceDispatchProxy.Create<TServiceContract>(netServiceProxy)!;
}
}
internal class NetServiceDispatchProxy : DispatchProxy
{
private INetServiceProxy? _netServiceProxy;
public static TServiceContract? Create<TServiceContract>(INetServiceProxy netServiceProxy)
{
object? proxy = DispatchProxy.Create<TServiceContract, NetServiceDispatchProxy>() as NetServiceDispatchProxy;
if (proxy == null)
return default;
((NetServiceDispatchProxy)proxy).Initialize(netServiceProxy);
return (TServiceContract)proxy;
}
/// <inheritdoc />
protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
{
var cts = new CancellationTokenSource(30000);
return _netServiceProxy?.Invoke(targetMethod, args, cts.Token);
}
private void Initialize(INetServiceProxy netServiceProxy)
{
_netServiceProxy = netServiceProxy;
}
}
Why does an error occur if IReadOnlyCollection
appears in the inheritance chain of `List'? Maybe something strange happend in Initialization or Serialization of the proxied Service?
I get a returned object IReadOnlyCollection from this method:
public async Task<IReadOnlyCollection<NotificationMarkResultDto>> MarkNotifications(AccountId accountKey, NotificationDto[] notificationsToUpdate)
{
var result = new List<NotificationMarkResultDto>(notificationsToUpdate.Length);
var notificationKeys = notificationsToUpdate.Select(x => x.NotificationKey).ToHashSet();
var notifications = await _uow.Notifications.GetNotifications(notificationKeys, accountKey);
foreach (var updateItem in notificationsToUpdate)
{
var foundNotification = notifications.FirstOrDefault(x => x.NotificationKey == updateItem.NotificationKey);
if (foundNotification != null)
{
foundNotification.Status = updateItem.Status ?? foundNotification.Status;
foundNotification.Importance = updateItem.Important switch
{
true => NotificationImportance.High,
false => NotificationImportance.Low,
_ => foundNotification.Importance,
};
result.Add(new NotificationMarkResultDto(updateItem.NotificationKey, foundNotification.Status, foundNotification.Importance));
}
else
{
result.Add(new NotificationMarkResultDto(updateItem.NotificationKey, "Notificaton not found"));
}
}
await _uow.SaveAsync();
return result;
}
This method is called in the controller, controller looks like this:
[HttpPost("marks")]
[Produces(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ValidationProblemDetails))]
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(ProblemDetails))]
[ProducesResponseType(StatusCodes.Status500InternalServerError, Type = typeof(ProblemDetails))]
public async Task<IReadOnlyCollection<NotificationMarkResultDto>> MarkNotifications([FromBody, Required] NotificationDto[] update)
{
return await _notificationService.MarkNotifications(params);
}
The whole error contains these lines:
{
"type": ";,
"title": "Unable to cast object of type '<Enumerate>d__1[Acp.Domain.Queries.Dtos.Notifications.NotificationMarkResultDto]' to type 'System.Collections.Generic.IReadOnlyCollection`1[Notifications.NotificationMarkResultDto]'.",
"status": 500,
"detail": "System.InvalidCastException: Unable to cast object of type '<Enumerate>d__1[NotificationMarkResultDto]' to type 'System.Collections.Generic.IReadOnlyCollection`1[Notifications.NotificationMarkResultDto]'.\n
at Net.NetCommHost.NetServiceProxy.TaskWrapper`1.<>c.<Wrap>b__0_0(Task`1 x)
\n at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()\n
at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)\n--- End of stack trace from previous location ---\n
at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)\n
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)\n--- End of stack trace from previous location ---\n
at Controllers.NotificationController.MarkNotifications(NotificationDto[] update) in /source/src/Controllers/NotificationController.cs:line 101\n at lambda_method305(Closure, Object)\n
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)\n
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)\n
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\n
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)\n
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\n
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\n
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)"
}
In the IDE, the compiler highlights explicit type conversion for service method in gray color as unnecessary code: "IDE0004 Cast is redudant"
return (IReadOnlyCollection<NotificationMarkResultDto>)result;
The error occurs only with ReverseProxy Server. With Normal Server everything is fine. ReverseProxy Server creates proxied Instances of services and injects them in the controller. In the proxied service I got the error:
Unable to cast object of type 'd__1[NotificationMarkResultDto]' to type 'System.Collections.Generic.IReadOnlyCollection`1[NotificationMarkResultDto]'.
When I debug the Reverse Proxy Server, go to the controller, then I can see the contents of the injected service in which an error occurs:
debug screenshot Injected NotificationService
These are methods where proxy services are created.
public INotificationService GetNotificationService()
{
return _host.Get<INotificationService>(INotificationService.NetServiceId, NetServiceFactory.Instance);
}
private sealed class NetServiceFactory : INetServiceFactory
{
public static readonly INetServiceFactory Instance = new NetServiceFactory();
/// <inheritdoc />
public string ResolveServiceAddress(string serviceKey)
{
throw new NotSupportedException();
}
/// <inheritdoc />
public TServiceContract CreateProxy<TServiceContract>(INetServiceProxy netServiceProxy)
{
return NetServiceDispatchProxy.Create<TServiceContract>(netServiceProxy)!;
}
}
internal class NetServiceDispatchProxy : DispatchProxy
{
private INetServiceProxy? _netServiceProxy;
public static TServiceContract? Create<TServiceContract>(INetServiceProxy netServiceProxy)
{
object? proxy = DispatchProxy.Create<TServiceContract, NetServiceDispatchProxy>() as NetServiceDispatchProxy;
if (proxy == null)
return default;
((NetServiceDispatchProxy)proxy).Initialize(netServiceProxy);
return (TServiceContract)proxy;
}
/// <inheritdoc />
protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
{
var cts = new CancellationTokenSource(30000);
return _netServiceProxy?.Invoke(targetMethod, args, cts.Token);
}
private void Initialize(INetServiceProxy netServiceProxy)
{
_netServiceProxy = netServiceProxy;
}
}
Why does an error occur if IReadOnlyCollection
appears in the inheritance chain of `List'? Maybe something strange happend in Initialization or Serialization of the proxied Service?
I get a returned object IReadOnlyCollection from this method:
public async Task<IReadOnlyCollection<NotificationMarkResultDto>> MarkNotifications(AccountId accountKey, NotificationDto[] notificationsToUpdate)
{
var result = new List<NotificationMarkResultDto>(notificationsToUpdate.Length);
var notificationKeys = notificationsToUpdate.Select(x => x.NotificationKey).ToHashSet();
var notifications = await _uow.Notifications.GetNotifications(notificationKeys, accountKey);
foreach (var updateItem in notificationsToUpdate)
{
var foundNotification = notifications.FirstOrDefault(x => x.NotificationKey == updateItem.NotificationKey);
if (foundNotification != null)
{
foundNotification.Status = updateItem.Status ?? foundNotification.Status;
foundNotification.Importance = updateItem.Important switch
{
true => NotificationImportance.High,
false => NotificationImportance.Low,
_ => foundNotification.Importance,
};
result.Add(new NotificationMarkResultDto(updateItem.NotificationKey, foundNotification.Status, foundNotification.Importance));
}
else
{
result.Add(new NotificationMarkResultDto(updateItem.NotificationKey, "Notificaton not found"));
}
}
await _uow.SaveAsync();
return result;
}
This method is called in the controller, controller looks like this:
[HttpPost("marks")]
[Produces(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ValidationProblemDetails))]
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(ProblemDetails))]
[ProducesResponseType(StatusCodes.Status500InternalServerError, Type = typeof(ProblemDetails))]
public async Task<IReadOnlyCollection<NotificationMarkResultDto>> MarkNotifications([FromBody, Required] NotificationDto[] update)
{
return await _notificationService.MarkNotifications(params);
}
The whole error contains these lines:
{
"type": "https://httpstatuses/500",
"title": "Unable to cast object of type '<Enumerate>d__1[Acp.Domain.Queries.Dtos.Notifications.NotificationMarkResultDto]' to type 'System.Collections.Generic.IReadOnlyCollection`1[Notifications.NotificationMarkResultDto]'.",
"status": 500,
"detail": "System.InvalidCastException: Unable to cast object of type '<Enumerate>d__1[NotificationMarkResultDto]' to type 'System.Collections.Generic.IReadOnlyCollection`1[Notifications.NotificationMarkResultDto]'.\n
at Net.NetCommHost.NetServiceProxy.TaskWrapper`1.<>c.<Wrap>b__0_0(Task`1 x)
\n at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()\n
at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)\n--- End of stack trace from previous location ---\n
at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)\n
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)\n--- End of stack trace from previous location ---\n
at Controllers.NotificationController.MarkNotifications(NotificationDto[] update) in /source/src/Controllers/NotificationController.cs:line 101\n at lambda_method305(Closure, Object)\n
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)\n
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)\n
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\n
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)\n
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\n
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\n
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)"
}
In the IDE, the compiler highlights explicit type conversion for service method in gray color as unnecessary code: "IDE0004 Cast is redudant"
return (IReadOnlyCollection<NotificationMarkResultDto>)result;
Share
Improve this question
edited Mar 21 at 13:18
Taya
asked Mar 13 at 11:10
TayaTaya
13 bronze badges
4
- 1 "the compiler highlights explicit type conversion in gray color as unnecessary code." What are you referring to and where is that in your code ? Like NotificationMarkResultDto is in the service and the controller isn't the same class and you expecting some type conversion somewhere occurring? – Ralf Commented Mar 13 at 14:16
- Are you make sure the runtime for different environment is the same? – Brando Zhang Commented Mar 14 at 6:14
- @BrandoZhang Update information: deployed the same version in docker, the error is still not reproducible in there. I checked the file history in git, the error has been appearing since the method began to return the IReadOnlyCollection type (previously the method was void) – Taya Commented Mar 14 at 8:25
- Consider either adding an Answer yourself, or closing the question. At the moment nobody except you might be able to write an Answer. – Peter B Commented Mar 17 at 21:06
1 Answer
Reset to default 0Problem was solved, when I set return value of MarkNotifications
from IReadOnlyCollection<NotificationMarkResultDto>
to NotificationMarkResult[]
and in NotificationMarkResultDto
were no setters written before (because I wanted to do that for the immutable response), but now they have been added.