Exception when adding new method in a working Service using gRPC-Web and protobuf-net - asp.net-core

I am getting the following exception:
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: The type initializer for 'DefaultProxyCache1' threw an exception. System.TypeInitializationException: The type initializer for 'DefaultProxyCache1' threw an exception. ---> System.ArgumentException: Invalid generic arguments
Parameter name: typeArguments
at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.MakeGenericMethod_impl(System.Reflection.RuntimeMethodInfo,System.Type[])
at System.Reflection.RuntimeMethodInfo.MakeGenericMethod (System.Type[] methodInstantiation) <0x342def8 + 0x000d6> in :0
at ProtoBuf.Grpc.Internal.ContractOperation.TryGetClientHelper () [0x0001b] in //src/protobuf-net.Grpc/Internal/ContractOperation.cs:291
at ProtoBuf.Grpc.Internal.ProxyEmitter.EmitFactory[TService] (ProtoBuf.Grpc.Configuration.BinderConfiguration binderConfig) [0x00477] in //src/protobuf-net.Grpc/Internal/ProxyEmitter.cs:238
at ProtoBuf.Grpc.Internal.ProxyEmitter.CreateFactory[TService] (ProtoBuf.Grpc.Configuration.BinderConfiguration binderConfig) [0x0006d] in //src/protobuf-net.Grpc/Internal/ProxyEmitter.cs:123
at ProtoBuf.Grpc.Configuration.ClientFactory+DefaultProxyCache`1[TService]..cctor () [0x00000] in //src/protobuf-net.Grpc/Configuration/ClientFactory.cs:81
My project uses gRPC-Web, Blazor web assembly and protobuf-net
This is my service contract:
[ServiceContract(Name = "Services.Customer")]
public interface ICustomerService
{
ValueTask<Customer> CreateCustomer(Customer customerDTO);
ValueTask<CustomerResultSet> GetCustomers();
}
The implementation is:
public class CustomerService : ICustomerService
{
private readonly CustomerUseCases customerLogic;
public CustomerService(CustomerUseCases customerLogic)
{
this.customerLogic = customerLogic;
}
public async ValueTask<Customer> CreateCustomer(Customer customerDTO)
{
var result = await customerLogic.CreateCustomer(customerDTO);
return customerDTO;
}
public async ValueTask<CustomerResultSet> GetCustomers()
{
CustomerResultSet result = new CustomerResultSet { Customers = await customerLogic.GetCustomer() };
return result;
}
}
As for the Datacontracts:
[DataContract]
public class CustomerResultSet
{
[DataMember(Order = 1)]
public IEnumerable<Customer> Customers { get; set; }
}
And,
[DataContract]
public partial class Customer
{
[DataMember(Order = 1)]
public int CustomerId { get; set; }
[DataMember(Order = 2)]
public string CustomerName { get; set; }
}
Before I was returning a List of customers in the service but I realize I needed a class to model the message in order to protobuf-net be able to serialize that is why CustomerResultSet. Still, it is not working.
Any help much appreciated

That is... odd. I can't repro it here, so I'm guessing it is something specific to Blazor. I've checked what the code does in the "regular" frameworks, and at least for me it seems to do the right things - using UnaryValueTaskAsync<Customer, Customer>() and UnaryValueTaskAsync<Empty, CustomerResultSet>(), which is what I would expect. I've improved the exception handling in that code path, to at least give us a clue what it is trying to do, so my suggestion is:
update to protobuf-net.Grpc version >= 1.0.119 (I'll get it deployed as soon as CI finishes)
retry, and let me know exactly what it says now
Alternatively, if you have a minimal repro including the blazor bits on, say, a GitHub repo, I can happily take a look there.
(tip: I try to keep an eye on both Stack Overflow and GitHub, but GitHub is probably more appropriate for this kind of question - I'd happily say that this is a bug, so: https://github.com/protobuf-net/protobuf-net.Grpc/issues)

I was having a similar problem.
System.InvalidOperationException: Error obtaining client-helper 'UnaryValueTaskAsync' (from: 'System.Guid', to: 'Test.DTO.OpResult'): Invalid generic arguments
My entire ServiceContract on that service stopped working. This happened after I added
ValueTask ChangeCompany(Guid companyGuid);
I changed it to
ValueTask ChangeCompany(string companyGuid);
And that got it working again. The error was a bit confusing since i wasn't using ChangeCompany, but like a said, not calls were working.

Related

Is it possible to inject dependencies into an NServiceBus Message Mutator?

I'd like to inject a dependency into an NServiceBus Message Mutator... since the lifetime of the Mutators is controlled by NServiceBus (and NSB wants a paramaterless constructor), constructor injection won't work...
any ideas?
UPDATE: Here is the code:
public class AddTransactionInformationToOutgoingHeaders :
IMutateOutgoingTransportMessages,
INeedInitialization
{
private readonly IProvideTransactionInformation transactionInformationProvider;
public void Init()
{
Configure.Instance.Configurer.ConfigureComponent<AddTransactionInformationToOutgoingHeaders>(DependencyLifecycle.InstancePerCall);
}
public AddTransactionInformationToOutgoingHeaders()
{
}
public AddTransactionInformationToOutgoingHeaders(IProvideTransactionInformation transactionInformationProvider)
{
this.transactionInformationProvider = transactionInformationProvider;
}
public void MutateOutgoing(object[] messages, TransportMessage transportMessage)
{
...
}
}
}
If I take away the empty ctor, I get this error message thrown from my ConfigureBus() call in Global.asax:
"No parameterless constructor defined for this object."
To get around this, I just kept one empty constructor for NServiceBus and then created a overloaded constructor that took my dependency that is managed by Unity.
It works.
Didn't know that mutators could work like that. It was my first time trying to inject a dependency into one.
UPDATE:
I got around this by using property injection on the mutator instead:
public class AddTransactionInformationToOutgoingHeaders : IMutateOutgoingTransportMessages, INeedInitialization
{
public IProvideTransactionInformation TransactionInformationProvider { get; set; }
public void Init()
{
Configure.Instance.Configurer.ConfigureComponent<AddTransactionInformationToOutgoingHeaders>(DependencyLifecycle.InstancePerCall);
}
public void MutateOutgoing(object[] messages, TransportMessage transportMessage)
{
...
}
}
Worked perfectly.
Pretty sure both constructor and property injection should work. What is the exception?

WCF callback occurs error when serialize

I am programming a Azure WCF application.
A datacontract defined as below:
[DataContract]
public class UserInfo
{
[DataMember]
public string UserName { get; set; }
[DataMember]
public int UserID { get; set; }
[DataMember]
public bool IsOnline { get; set; }
}
then I define a datacontract in my WCF service:
[DataContract(Name="UserInfo")]
public class ServiceUserInfo : UserInfo
{
[IgnoreDataMember]
public ICallback Callback { get; set; }
}
Then in the service contract, it will callback to client, the method as below
private void NoticeUsers(UserInfo currentuser)
{
var users = UserManager.GetAllActiveUsers();
foreach (var user in users)
{
if (user.UserName == currentuser.UserName)
continue;
user.Callback.UpdateUserList(currentuser);
}
}
Actually I pass a ServiceUserInfo object as parameter to the NoticeUsers method. Then an error will occurs as below:
There was an error while trying to serialize parameter http://tempuri.org/:user. The InnerException message was 'Type 'WCFServiceWebRole.ServiceUserInfo' with data contract name 'UserInfo:http://schemas.datacontract.org/2004/07/WCFServiceWebRole' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.
I am not able to find solution for this issue.Please help.
I think I have found the root cause of the issue, however I do not know why.
The problem is caused by the Namespace attribute of the Service contract.
I didn't set the namespace of my service contract interface and data contract interface. I thought it would be set by default and it won't cause any problem. But actually the issue of this thread is caused by the Namespace attribute. I set a Namespace attribute for both service contract and data contract, of course the same namespace, then it worked. The problem never happens again.
However, I do not know why it caused this issue. If I do not set Namespace, it will be a default value of "http://tempuri.org", isn't it?

toList() System.InvalidCastException was unhandled by user code

I have written a WCF service using LINQ to SQL (using the following article at codeporject). I am facing the invalid cast exception when i invoke the .ToList() method of an object after i have already made a wcf function call of the same service against the same database.
The exception is:
System.InvalidCastException was unhandled by user code
Message=Specified cast is not valid.
Source=System.Data
StackTrace:
at System.Data.SqlClient.SqlBuffer.get_Int64()
at System.Data.SqlClient.SqlDataReader.GetInt64(Int32 i)
at Read_Command(ObjectMaterializer`1 )
at System.Data.Linq.SqlClient.ObjectReaderCompiler.ObjectReader`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at SystemsManager.ACS.GetCommands(Int64 agentId) in E:\Projects\SystemsManager\AgentControlService\ACS.svc.cs:line 167
at SyncInvokeGetCommands(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
InnerException:
The specific line i am having issue is with the ToList() method
public List<Command> GetCommands(long agentId)
{
var cmd = from command in db.Command where (command.AgentId == agentId) select command;
return cmd.ToList();
}
When debugging, the return statment throws exception. When view the value of cmd.ToList() in Quick Watch of VS 2010, the exception is shown.
Now the strangest thing is: Pressing "Re-Evaluate" button a couple of times changes the exception to required object list in Quick watch. Infact i have to press "Re-evaluate" at least three times.
I have generated client using svcutil tool after my most recent changes to the service/database.
I am calling the method using the following code from a windows service:
var agent = client.GetAgentByIpAddress(myIPAddress);
client.Close();
if (agent != null)
{
if (agent.AgentId != -1)
{
client = new ACSClient();
var command = client.GetCommands(agent.AgentId);
.....
Here is the model of Command in the interface of the wcf service.
[DataContract]
[Table(Name = "Command")]
public class Command
{
[DataMember, Column(IsPrimaryKey = true, Name = "Command_Id", AutoSync = AutoSync.OnInsert, IsDbGenerated = true, DbType = "Bigint NOT null identity")]
public long CommandId { get; set; }
[DataMember, Column(Name = "Agent_Id")]
public long AgentId { get; set; }
[DataMember, Column(Name = "Name")]
public string CommandName { get; set; }
[DataMember, Column(Name = "Paramters")]
public string CommandParamters { get; set; }
[DataMember, Column(Name = "Is_Fetched")]
public bool IsFectched { get; set; }
[DataMember, Column(Name = "Status")]
public long Status { get; set; }
[DataMember, Column(Name = "Response")]
public string Response { get; set; }
[DataMember, Column(Name = "Created")]
public DateTime Created { get; set; }
[DataMember, Column(Name = "Last_Modified")]
public DateTime LastModified { get; set; }
[DataMember, Column(Name = "Is_Enabled")]
public bool IsEnabled { get; set; }
}
Important thing is: My database file is located in AppData folder of the WCF service. I am using only one instance of db object (refer to 1st code block above) throughout my wcf service and i am wondering if this could be cause of the problem???
Also, i have called a couple of similar method of this very same wcf service from a desktop application but i have not faced any such issue.
Please help. if more details are needed, please state so.. The only thing that can come to mind is that perhaps the database is in use and when another connection is made to the database by the service, it fails. and retrying it a couple of times using the Quick Watch > Re-evaluate button displays the required values in the watch window without throwing any error.
Kindly help on this one. Quick responses are highly appreciated.
Thanks.
Steve
Never mind guys. I solved it.
For anyone else who is getting invalid cast exception, here is the solution.
The error only occurs when actual class model is different that the database.
If you have created the class model by hand coding it, the you must match each column name of the table to your corresponding class. LINQ to sql encounters error when it cannot convert a database type to .Net type and throws invalid cast exception.
So in most cases, either fixing the error manually in the model class or regenerating the class will solve the problem.

System.Threading.Tasks.Task - cannot be serialized because it does not have a parameterless constructor.

I am currently using the WCF Web API and it is working great with synchronous tasks.
However, when I try and implement asynchronous operations using Task/Task like so:
[WebGet(UriTemplate = "landmark")]
Task<IEnumerable<Closest>> GetLandmarkAsync(float latitude, float longtitude)
{
return Task.Factory.StartNew(() => CalculateClosestThing(latitude, longtitude));
}
I am getting this error:
System.Threading.Tasks.Task`1[System.Collections.Generic.IEnumerable`1[ContentRepository.Data.Entities.Closest]] cannot be serialized because it does not have a parameterless constructor.
Now, the first thing I did was check the Closest Class and add a parameterless constructor like so:
public class Closest
{
public Closest() { }
public double Distance { get; set; }
public string Name { get; set; }
}
But I'm still getting the same error. I've tried everything and clearly there is a parameterless constructor on the class. Has anyone ever experienced this? Any ideas?
Ensure you new up a WebApiConfiguration obj (derived from HttpConfiguration) and set it as the default Http configuration with a call to routes.SetDefaultHttpConfiguration() in the host (I'm using an MVC host).
I had the same problem as you before I switched from HttpConfiguration to WebApiConfiguration.
For more details see here.
Give these a read:
http://arbel.net/2011/06/04/wcf-tasks/
http://msdn.microsoft.com/en-us/library/ms730059.aspx
http://www.dotnetcurry.com/ShowArticle.aspx?ID=237

WCF and ServiceKnownType with many assemblies

WCF Question. I'm having trouble with multiple assemblies and inheritances and data contracts.
Senario: data contracts binaries are shared
Common.dll
[DataContract]
public abstract class Command
{
[DataMember]
public Guid Id { get; set; }
public Command(Guid id)
{
Id = id;
}
}
assembly1.dll
[DataContract]
public class DeleteStuff : Command
{
public DeleteStuff(Guid id)
: base(id) { }
[DataMember]
public int StuffToDeleteID { get; set; }
}
assembly2.dll
[DataContract]
public class DeleteSomeOtherStuff : Command
{
public DeleteSomeOtherStuff(Guid id)
: base(id) { }
[DataMember]
public int SomeOtherID { get; set; }
}
Service Contract
[ServiceContract]
[ServiceKnownType("GetKnownTypes", typeof(DerivedType))]
public partial interface ICommandsServiceContract
{
[OperationContract]
void Execute(IEnumerable<Command> command);
}
DerivedType class, method GetKnownTypes
public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
{
//Works!*!*! but hard-coded, wont work in big picture since i dont know all the classes
//return new List<Type> { typeof(DeleteSomeOtherStuff), typeof(DeleteStuff) };
//DOESNT WORK!!
Type type = typeof(Command);
IEnumerable<Type> types = AppDomain.CurrentDomain.GetAssemblies().ToList()
.SelectMany(a => a.GetTypes()
.Where(t => type.IsAssignableFrom(t)));
IEnumerable<Type> j = types.ToArray();
return j;
}
If I put a break point on return j; above, when the service first runs it has the correct assembly types that inherit from Command. Then the client spins up and as soon as I send a DeleteSomeOtherStuff to the service it explodes with an error on the SelectMany clause.
Server Error in '/' Application.
Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
Source Error:
Line 25: var type = typeof(Command);
Line 26: var types = AppDomain.CurrentDomain.GetAssemblies().ToList()
Line 27: .SelectMany(a => a.GetTypes())
Line 28: .Where(t => type.IsAssignableFrom(t));
Line 29:
Line 27 is marked as the error.
I tried throwing the array list in a static variable to cache it when the service first runs and then it would be available when its called by a consumer but that had the same error.
I'm using a basic channel factory from the client.
Ideas?? I can't limit to a single assembly.
Thanks!!
In your classes that inherit from Command, add the [KnownType] attribute. For example,
[DataContract]
[KnownType(typeof(Command))]
public class DeleteStuff
{
}