-
Notifications
You must be signed in to change notification settings - Fork 289
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WCF: action is assigned with null if operation name is not defined(#169) #170
WCF: action is assigned with null if operation name is not defined(#169) #170
Conversation
|
@tamilaban Thanks for the contribution! Would you mind adding a test that covers this case? |
Codecov Report
@@ Coverage Diff @@
## main #170 +/- ##
==========================================
+ Coverage 78.60% 78.62% +0.01%
==========================================
Files 89 89
Lines 2323 2325 +2
==========================================
+ Hits 1826 1828 +2
Misses 497 497
|
HI @CodeBlanch , I could not make the action as null, I have assigned the action name to an empty string and updated the unit test in adherence . Can you please have a look ? |
Hi @CodeBlanch , Can you please review this PR ? |
@mconnew Hey I could use some help on this if you have any free cycles. So our telemetry for WCF calls does this...
How we find ContractName + OperationName is we pre-build a lookup dictionary: Lines 67 to 73 in 9373eb5
When we have an Now the user is reporting a contract without action: [ServiceContract(Namespace = "http://opentelemetry.io/", Name = "Service", SessionMode = SessionMode.Allowed)]
public interface IServiceContract
{
[OperationContract]
Task<ServiceResponse> ExecuteAsync(ServiceRequest request);
[OperationContract(Action = "")]
Task<ServiceResponse> ExecuteWithEmptyActionNameAsync(ServiceRequest request);
} That sort of accidentally still works because the empty action still ends up on the lookup. But if contract has multiple empty actions... [ServiceContract(Namespace = "http://opentelemetry.io/", Name = "Service", SessionMode = SessionMode.Allowed)]
public interface IServiceContract
{
[OperationContract]
Task<ServiceResponse> ExecuteAsync(ServiceRequest request);
[OperationContract(Action = "")]
Task<ServiceResponse> ExecuteWithEmptyActionNameAsync(ServiceRequest request);
[OperationContract(Action = "")]
Task<ServiceResponse> SomeOtherOperationWithEmptyActionNameAsync(ServiceRequest request);
} ...then the telemetry is going to lie and always pick the first empty entry. What I need is some way in... public object BeforeSendRequest(ref Message request, IClientChannel channel) ...to get at the operation data. I don't see anything public to help. It seems like there is private stuff like Any ideas? |
@CodeBlanch, does an empty Action actually work for multiple operations? Here's the default code where WCF looks up which operation is being executed based on the incoming message, and as you can see it uses a dictionary with the action as the key. So two operations with the same action won't work by default. I took a deeper look at the code to see if there should be an exception on service startup, and it looks like there should be as ActionDemuxer is calling HybridDictionary.Add which throws on duplicates. This is only with the default behavior though. There is another alternative how this might work. If an implementation of The only way I am aware of where that you can have two operations with the same action without it throwing when you start the service is to use a custom |
@mconnew Thanks for the great info! I did a bit of testing. With two operations defined with |
It's allowed on the client as you can have a Task based and synchronous version of the same operation in a contract. They must be equivalent though. I think it might even modify the name so they both have the same operation name. There's no ambiguity about what to do there. It's only on the server side that you can't have the ambiguity. |
Thanks much @CodeBlanch and @mconnew . |
public string DisplayName { get { return _displayName ?? OperationName; } set { _displayName = (value ?? throw new ArgumentNullException("value")); }