{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/orleans/issues/965","labels_url":"https://api.github.com/repos/dotnet/orleans/issues/965/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/orleans/issues/965/comments","events_url":"https://api.github.com/repos/dotnet/orleans/issues/965/events","html_url":"https://github.com/dotnet/orleans/pull/965","id":114157174,"number":965,"title":"Feature: Per-Grain-class Request Interceptors","user":{"login":"ReubenBond","id":203839,"avatar_url":"https://avatars.githubusercontent.com/u/203839?v=3","gravatar_id":"","url":"https://api.github.com/users/ReubenBond","html_url":"https://github.com/ReubenBond","followers_url":"https://api.github.com/users/ReubenBond/followers","following_url":"https://api.github.com/users/ReubenBond/following{/other_user}","gists_url":"https://api.github.com/users/ReubenBond/gists{/gist_id}","starred_url":"https://api.github.com/users/ReubenBond/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ReubenBond/subscriptions","organizations_url":"https://api.github.com/users/ReubenBond/orgs","repos_url":"https://api.github.com/users/ReubenBond/repos","events_url":"https://api.github.com/users/ReubenBond/events{/privacy}","received_events_url":"https://api.github.com/users/ReubenBond/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/dotnet/orleans/labels/cla-already-signed","name":"cla-already-signed","color":"009800"},{"url":"https://api.github.com/repos/dotnet/orleans/labels/enhancement","name":"enhancement","color":"84b6eb"},{"url":"https://api.github.com/repos/dotnet/orleans/labels/work-in-progress","name":"work-in-progress","color":"fad8c7"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":38,"created_at":"2015-10-29T22:03:07Z","updated_at":"2015-11-03T13:10:29Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/dotnet/orleans/pulls/965","html_url":"https://github.com/dotnet/orleans/pull/965","diff_url":"https://github.com/dotnet/orleans/pull/965.diff","patch_url":"https://github.com/dotnet/orleans/pull/965.patch"},"body":"This feature allows users to override `Grain.Invoke(InvokeMethodRequest request, IGrainMethodInvoker invoker)` in order to perform request interception on a per-Grain-class level.\r\n\r\nAs requested by @yevhen in #749.\r\n\r\nExample:\r\n```C#\r\npublic class InterceptRequestGrain : Grain, ISomeGrain \r\n{\r\n  protected override Task<object> Invoke(InvokeMethodRequest request, IGrainMethodInvoker invoker)\r\n  {\r\n    RequestContext.Set(\"InterceptedValue\", 74);\r\n    return base.Invoke(request, invoker);\r\n  }\r\n\r\n  // Other methods...\r\n}\r\n```"},"comment":{"url":"https://api.github.com/repos/dotnet/orleans/issues/comments/153347638","html_url":"https://github.com/dotnet/orleans/pull/965#issuecomment-153347638","issue_url":"https://api.github.com/repos/dotnet/orleans/issues/965","id":153347638,"user":{"login":"ReubenBond","id":203839,"avatar_url":"https://avatars.githubusercontent.com/u/203839?v=3","gravatar_id":"","url":"https://api.github.com/users/ReubenBond","html_url":"https://github.com/ReubenBond","followers_url":"https://api.github.com/users/ReubenBond/followers","following_url":"https://api.github.com/users/ReubenBond/following{/other_user}","gists_url":"https://api.github.com/users/ReubenBond/gists{/gist_id}","starred_url":"https://api.github.com/users/ReubenBond/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ReubenBond/subscriptions","organizations_url":"https://api.github.com/users/ReubenBond/orgs","repos_url":"https://api.github.com/users/ReubenBond/repos","events_url":"https://api.github.com/users/ReubenBond/events{/privacy}","received_events_url":"https://api.github.com/users/ReubenBond/received_events","type":"User","site_admin":false},"created_at":"2015-11-03T13:10:29Z","updated_at":"2015-11-03T13:10:29Z","body":"Great, I agree with that.\r\nHow's this, then?\r\n```C#\r\npublic class MyGrain : Grain, IMyGrain\r\n{\r\n  protected override Task<object> Invoke(InvokeMethodRequest request, MethodInfo method)\r\n  {\r\n     this.log.Info($\"{method.Name} was called\");\r\n     return base.Invoke(request);\r\n  }\r\n}\r\n```\r\n\r\nAlternatively we can do:\r\n```C#\r\npublic class MyGrain : Grain, IMyGrain\r\n{\r\n  protected override Task<object> Invoke(InvokeMethodRequest request)\r\n  {\r\n     var method = this.GetMethod(request);\r\n     this.log.Info($\"{method.Name} was called\");\r\n     return base.Invoke(request);\r\n  }\r\n}\r\n```\r\n\r\nEither way, likely I would create a similar jump table to what's in the current generated `IGrainMethodInvoker` impl, but which returns a static `MethodInfo` instance for the method corresponding to the `request` instead of invoking the request.\r\nSomething like `MethodInfo GetMethod(InvokeMethodRequest request)`."}}