{"action":"created","comment":{"url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/pulls/comments/173234494","pull_request_review_id":102390814,"id":173234494,"diff_hunk":"@@ -0,0 +1,763 @@\n+﻿namespace Microsoft.ApplicationInsights.Web.Implementation\n+{\n+    using System;\n+    using System.Collections;\n+    using System.Collections.Generic;\n+    using System.Globalization;\n+    using System.Reflection;\n+    using System.Reflection.Emit;\n+    using Microsoft.ApplicationInsights.DataContracts;\n+    using Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing;\n+\n+    internal static class ExceptionHandlersInjector\n+    {\n+        // we only support ASP.NET 5 for now \n+        // and may extend list of supported versions if there will be a business need \n+        private const int MinimumMvcVersion = 5;\n+        private const int MinimumWebApiVersion = 5;\n+\n+        private const string AssemblyName = \"Microsoft.ApplicationInsights.ExceptionTracking\";\n+        private const string MvcHandlerName = AssemblyName + \".MvcExceptionFilter\";\n+        private const string WebApiHandlerName = AssemblyName + \".WebApiExceptionLogger\";\n+\n+        private const string TelemetryClientFieldName = \"telemetryClient\";\n+        private const string IsAutoInjectedFieldName = \"IsAutoInjected\";\n+        private const string OnExceptionMethodName = \"OnException\";\n+        private const string OnLogMethodName = \"Log\";\n+\n+        /// <summary>\n+        /// Forces injection of MVC5 exception filter and WebAPI2 exception logger into the global configurations.\n+        /// </summary>\n+        /// <remarks>\n+        /// <para>Injection is attempted each time method is called. However if the filter/logger was injected already, injection is skipped.</para>\n+        /// <para>Use this method only when you can guarantee it's called once per AppDomain.</para>\n+        /// </remarks>\n+        internal static void Inject(TelemetryClient telemetryClient)\n+        {\n+            try\n+            {\n+                WebEventSource.Log.InjectionStarted();\n+\n+                var trackExceptionMethod = GetMethodOrFail(typeof(TelemetryClient), \"TrackException\", new[] { typeof(ExceptionTelemetry) });\n+                var exceptionTelemetryCtor = GetConstructorOrFail(typeof(ExceptionTelemetry), new[] { typeof(Exception) });\n+\n+                var assemblyName = new AssemblyName(AssemblyName);\n+                var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);\n+\n+                var moduleBuilder = assemblyBuilder.DefineDynamicModule(AssemblyName);\n+\n+                AddMvcFilter(\n+                    telemetryClient,\n+                    moduleBuilder,\n+                    exceptionTelemetryCtor,\n+                    trackExceptionMethod);\n+\n+                AddWebApiExceptionLogger(\n+                    telemetryClient,\n+                    moduleBuilder,\n+                    exceptionTelemetryCtor,\n+                    trackExceptionMethod);\n+            }\n+            catch (Exception e)\n+            {\n+                WebEventSource.Log.InjectionUnknownError(e.ToString());\n+            }\n+\n+            WebEventSource.Log.InjectionCompleted();\n+        }\n+\n+        #region Mvc\n+\n+        /// <summary>\n+        /// Generates new MVC5 filter class implementing HandleErrorAttribute and adds instance of it to the GlobalFilterCollection.\n+        /// </summary>\n+        /// <param name=\"telemetryClient\"><see cref=\"TelemetryClient\"/> instance.</param>\n+        /// <param name=\"moduleBuilder\"><see cref=\"ModuleBuilder\"/> to define type in.</param>\n+        /// <param name=\"exceptionTelemetryCtor\"><see cref=\"ConstructorInfo\"/> of default constructor of <see cref=\"ExceptionTelemetry\"/>.</param>\n+        /// <param name=\"trackExceptionMethod\"><see cref=\"MethodInfo\"/> of <see cref=\"TelemetryClient.TrackException(ExceptionTelemetry)\"/>.</param>\n+        private static void AddMvcFilter(\n+            TelemetryClient telemetryClient,\n+            ModuleBuilder moduleBuilder,\n+            ConstructorInfo exceptionTelemetryCtor,\n+            MethodInfo trackExceptionMethod)\n+        {\n+            // This method emits following code:\n+            // [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]\n+            // public class MvcExceptionFilter : HandleErrorAttribute\n+            // {\n+            //     public const bool IsAutoInjected = true;\n+            //     private readonly TelemetryClient telemetryClient = new TelemetryClient();\n+            //     \n+            //     public MvcExceptionFilter(TelemetryClient tc) : base()\n+            //     {\n+            //         telemetryClient = tc;\n+            //     }\n+            //     \n+            //     public override void OnException(ExceptionContext filterContext)\n+            //     {\n+            //        if (filterContext != null && filterContext.HttpContext != null && filterContext.Exception != null && filterContext.HttpContext.IsCustomErrorEnabled)\n+            //            telemetryClient.TrackException(new ExceptionTelemetry(filterContext.Exception));\n+            //        base.OnException(filterContext);\n+            //     }\n+            // }\n+            // \n+            // GlobalFilters.Filters.Add(new MvcExceptionFilter(new TelemetryClient()));\n+            try\n+            {\n+                // Get HandleErrorAttribute, make sure it's resolved and MVC version is supported\n+                var handleErrorType = GetTypeOrFail(\"System.Web.Mvc.HandleErrorAttribute, System.Web.Mvc\");\n+                if (handleErrorType.Assembly.GetName().Version.Major < MinimumMvcVersion)\n+                {\n+                    WebEventSource.Log.InjectionVersionNotSupported(handleErrorType.Assembly.GetName().Version.ToString(), \"MVC\");\n+                    return;\n+                }\n+\n+                // get global filter collection\n+                GetMvcGlobalFiltersOrFail(out dynamic globalFilters, out Type globalFilterCollectionType);\n+\n+                if (!NeedToInjectMvc(globalFilters))\n+                {\n+                    // there is another filter in the collection that has IsAutoInjected const field set to true - stop injection.\n+                    return;\n+                }\n+\n+                var exceptionContextType = GetTypeOrFail(\"System.Web.Mvc.ExceptionContext, System.Web.Mvc\");\n+                var exceptionGetter = GetMethodOrFail(exceptionContextType, \"get_Exception\");\n+\n+                var controllerContextType = GetTypeOrFail(\"System.Web.Mvc.ControllerContext, System.Web.Mvc\");\n+                var httpContextGetter = GetMethodOrFail(controllerContextType, \"get_HttpContext\");\n+\n+                var baseOnException = GetMethodOrFail(handleErrorType, OnExceptionMethodName, new[] { exceptionContextType });\n+                var addFilter = GetMethodOrFail(globalFilterCollectionType, \"Add\", new[] { typeof(object) });\n+\n+                // HttpContextBase requires full assembly name to be resolved\n+                // even though version 4.0.0.0 (CLR version) is specified, it will be resolved to the latest .NET System.Web installed\n+                var httpContextBaseType = GetTypeOrFail(\"System.Web.HttpContextBase, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\");\n+                var isCustomErrorEnabled = GetMethodOrFail(httpContextBaseType, \"get_IsCustomErrorEnabled\");\n+\n+                // build a type for exception filter.\n+                TypeBuilder typeBuilder = moduleBuilder.DefineType(MvcHandlerName, TypeAttributes.Public | TypeAttributes.Class, handleErrorType);\n+                typeBuilder.SetCustomAttribute(GetUsageAttributeOrFail());\n+                var telemetryClientField = typeBuilder.DefineField(TelemetryClientFieldName, typeof(TelemetryClient), FieldAttributes.Private);\n+\n+                DefineAutoInjectedField(typeBuilder);\n+\n+                // emit constructor that assigns telemetry client field\n+                var handleErrorBaseCtor = GetConstructorOrFail(handleErrorType, new Type[0]);\n+                EmitConstructor(typeBuilder, typeof(TelemetryClient), telemetryClientField, handleErrorBaseCtor);\n+\n+                // emit OnException method that handles exception\n+                EmitMvcOnException(\n+                    typeBuilder,\n+                    exceptionContextType,\n+                    telemetryClientField,\n+                    exceptionGetter,\n+                    trackExceptionMethod,\n+                    baseOnException,\n+                    exceptionTelemetryCtor,\n+                    httpContextBaseType,\n+                    httpContextGetter,\n+                    isCustomErrorEnabled);\n+\n+                // create error handler type\n+                var handlerType = typeBuilder.CreateType();\n+\n+                // add handler to global filters\n+                var mvcFilter = Activator.CreateInstance(handlerType, telemetryClient);\n+                addFilter.Invoke(globalFilters, new[] { mvcFilter });\n+            }\n+            catch (ResolutionException e)\n+            {\n+                // some of the required types/methods/properties/etc were not found.\n+                // it may indicate we are dealing with a new version of MVC library\n+                // handle it and log here, we may still succeed with WebApi injection\n+                WebEventSource.Log.InjectionFailed(\"MVC\", e.ToInvariantString());\n+            }\n+        }\n+\n+        /// <summary>\n+        /// Emits OnException method.\n+        /// </summary>\n+        /// <param name=\"typeBuilder\">MVCExceptionFilter type builder.</param>\n+        /// <param name=\"exceptionContextType\">Type of ExceptionContext.</param>\n+        /// <param name=\"telemetryClientField\">FieldInfo of MVCExceptionFilter.telemetryClient.</param>\n+        /// <param name=\"exceptionGetter\">MethodInfo to get ExceptionContext.Exception.</param>\n+        /// <param name=\"trackException\">MethodInfo of TelemetryClient.TrackException(ExceptionTelemetry).</param>\n+        /// <param name=\"baseOnException\">MethodInfo of base (HandleErrorAttribute) OnException method.</param>\n+        /// <param name=\"exceptionTelemetryCtor\">ConstructorInfo of ExceptionTelemetry.</param>\n+        /// <param name=\"httpContextBaseType\">Type of HttpContextBase.</param>\n+        /// <param name=\"httpContextGetter\">MethodInfo to get ExceptionContext.HttpContext.</param>\n+        /// <param name=\"isCustomErrorEnabled\">MethodInfo to get ExceptionContext.HttpContextBase.IsCustomErrorEnabled.</param>\n+        private static void EmitMvcOnException(\n+            TypeBuilder typeBuilder,\n+            Type exceptionContextType,\n+            FieldInfo telemetryClientField,\n+            MethodInfo exceptionGetter,\n+            MethodInfo trackException,\n+            MethodInfo baseOnException,\n+            ConstructorInfo exceptionTelemetryCtor,\n+            Type httpContextBaseType,\n+            MethodInfo httpContextGetter,\n+            MethodInfo isCustomErrorEnabled)\n+        {\n+            // This method emits following code:\n+            // public override void OnException(ExceptionContext filterContext)\n+            // {\n+            //    if (filterContext != null && filterContext.HttpContext != null && filterContext.Exception != null && filterContext.HttpContext.IsCustomErrorEnabled)\n+            //        telemetryClient.TrackException(new ExceptionTelemetry(filterContext.Exception));\n+            //    base.OnException(filterContext);\n+            // }  \n+             \n+            // defines public override void OnException(ExceptionContext filterContext)\n+            var onException = typeBuilder.DefineMethod(\n+                OnExceptionMethodName,\n+                MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig,\n+                null,\n+                new[] { exceptionContextType });\n+            var il = onException.GetILGenerator();\n+\n+            Label track = il.DefineLabel();\n+            Label end = il.DefineLabel();\n+            Label n1 = il.DefineLabel();\n+            Label n2 = il.DefineLabel();\n+            Label n3 = il.DefineLabel();\n+\n+            var httpContext = il.DeclareLocal(httpContextBaseType);\n+            var exception = il.DeclareLocal(typeof(Exception));\n+            var v2 = il.DeclareLocal(typeof(bool));\n+            var v3 = il.DeclareLocal(typeof(bool));\n+            var v4 = il.DeclareLocal(typeof(bool));\n+            var v5 = il.DeclareLocal(typeof(bool));\n+\n+            // if filterContext is null, goto the end\n+            il.Emit(OpCodes.Ldarg_1);\n+            il.Emit(OpCodes.Ldnull);\n+            il.Emit(OpCodes.Ceq);\n+            il.Emit(OpCodes.Stloc, v2);\n+            il.Emit(OpCodes.Ldloc, v2);\n+            il.Emit(OpCodes.Brfalse_S, n1);\n+            il.Emit(OpCodes.Br_S, end);\n+\n+            // if filterContext.HttpContext is null, goto the end\n+            il.MarkLabel(n1);\n+            il.Emit(OpCodes.Ldarg_1);\n+            il.Emit(OpCodes.Callvirt, httpContextGetter);\n+            il.Emit(OpCodes.Stloc, httpContext);\n+            il.Emit(OpCodes.Ldloc, httpContext);\n+            il.Emit(OpCodes.Ldnull);\n+            il.Emit(OpCodes.Ceq);\n+            il.Emit(OpCodes.Stloc, v3);\n+            il.Emit(OpCodes.Ldloc, v3);\n+            il.Emit(OpCodes.Brfalse_S, n2);\n+            il.Emit(OpCodes.Br_S, end);\n+\n+            // if filterContext.Exception is null, goto the end\n+            il.MarkLabel(n2);\n+            il.Emit(OpCodes.Ldarg_1);\n+            il.Emit(OpCodes.Callvirt, exceptionGetter);\n+            il.Emit(OpCodes.Stloc, exception);\n+            il.Emit(OpCodes.Ldloc, exception);\n+            il.Emit(OpCodes.Ldnull);\n+            il.Emit(OpCodes.Ceq);\n+            il.Emit(OpCodes.Stloc_S, v4);\n+            il.Emit(OpCodes.Ldloc_S, v4);\n+            il.Emit(OpCodes.Brfalse_S, n3);\n+            il.Emit(OpCodes.Br_S, end);\n+\n+            // if filterContext.HttpContext.IsCustomErrorEnabled is false, goto the end\n+            il.MarkLabel(n3);\n+            il.Emit(OpCodes.Ldloc, httpContext);\n+            il.Emit(OpCodes.Callvirt, isCustomErrorEnabled);\n+            il.Emit(OpCodes.Ldc_I4_0);\n+            il.Emit(OpCodes.Ceq);\n+            il.Emit(OpCodes.Stloc_S, v5);\n+            il.Emit(OpCodes.Ldloc_S, v5);\n+            il.Emit(OpCodes.Brfalse_S, track);\n+            il.Emit(OpCodes.Br_S, end);\n+\n+            // telemetryClient.TrackException(new ExceptionTelemetry(filterContext.Exception))\n+            il.MarkLabel(track);\n+            il.Emit(OpCodes.Ldarg_0);\n+            il.Emit(OpCodes.Ldfld, telemetryClientField);\n+            il.Emit(OpCodes.Ldloc, exception);\n+            il.Emit(OpCodes.Newobj, exceptionTelemetryCtor);\n+            il.Emit(OpCodes.Callvirt, trackException);\n+            il.Emit(OpCodes.Br_S, end);\n+\n+            // call base.OnException(filterContext);\n+            il.MarkLabel(end);\n+            il.Emit(OpCodes.Ldarg_0);\n+            il.Emit(OpCodes.Ldarg_1);\n+            il.Emit(OpCodes.Call, baseOnException);\n+\n+            il.Emit(OpCodes.Ret);\n+        }\n+\n+        /// <summary>\n+        /// Gets GlobalFilters.Filters property value. If not resolved, or is null, fails with <see cref=\"ResolutionException\"/>.\n+        /// </summary>\n+        /// <param name=\"globalFilters\">Resolved GlobalFilters.Filters instance.</param>\n+        /// <param name=\"globalFilterCollectionType\">Resolved GlobalFilterCollection type.</param>\n+        private static void GetMvcGlobalFiltersOrFail(out dynamic globalFilters, out Type globalFilterCollectionType)\n+        {\n+            globalFilterCollectionType = GetTypeOrFail(\"System.Web.Mvc.GlobalFilterCollection, System.Web.Mvc\");\n+\n+            var globalFiltersType = GetTypeOrFail(\"System.Web.Mvc.GlobalFilters, System.Web.Mvc\");\n+            globalFilters = GetStaticPropertyValueOrFail(globalFiltersType, \"Filters\");\n+        }\n+\n+        /// <summary>\n+        /// Checks if another auto injected filter was already added into the filter collection.\n+        /// </summary>\n+        /// <param name=\"globalFilters\">GlobalFilters.Filters value of GlobalFilterCollection type.</param>\n+        /// <returns>True if injection needs to be done, false when collection already contains another auto injected filter.</returns>\n+        private static bool NeedToInjectMvc(dynamic globalFilters)\n+        {\n+            var filters = (IEnumerable)globalFilters;\n+\n+            // GlobalFilterCollection must implements IEnumerable, if not - fail.\n+            if (filters == null)\n+            {\n+                throw new ResolutionException(string.Format(CultureInfo.InvariantCulture, \"Unexpected type of GlobalFilterCollection {0}\", globalFilters.GetType()));\n+            }\n+\n+            var mvcFilterType = GetTypeOrFail(\"System.Web.Mvc.Filter, System.Web.Mvc\");\n+            var mvcFilterInstanceProp = GetPropertyOrFail(mvcFilterType, \"Instance\");\n+\n+            // iterate over the filters\n+            foreach (var filter in filters)\n+            {\n+                if (filter.GetType() != mvcFilterType)\n+                {\n+                    throw new ResolutionException(string.Format(CultureInfo.InvariantCulture, \"Unexpected type of MVC Filter {0}\", filter.GetType()));\n+                }\n+\n+                var instance = mvcFilterInstanceProp.GetValue(filter);\n+                if (instance == null)\n+                {\n+                    throw new ResolutionException($\"MVC Filter does not have Instance property\");\n+                }\n+\n+                var isAutoInjectedField = instance.GetType().GetField(IsAutoInjectedFieldName, BindingFlags.Public | BindingFlags.Static);\n+                if (isAutoInjectedField != null && (bool)isAutoInjectedField.GetValue(null))\n+                {\n+                    // isAutoInjected public const field (when true) indicates that our filter is already injected by other component.\n+                    // return false and stop MVC injection\n+                    WebEventSource.Log.InjectionSkipped(instance.GetType().AssemblyQualifiedName, \"MVC\");\n+                    return false;\n+                }\n+            }\n+\n+            return true;\n+        }\n+\n+        #endregion\n+\n+        #region WebApi\n+\n+        /// <summary>\n+        /// Generates new WebAPI2 exception logger class implementing ExceptionLogger and adds instance of it to the GlobalConfiguration.Configuration.Services of IExceptionLogger type.\n+        /// </summary>\n+        /// <param name=\"telemetryClient\"><see cref=\"TelemetryClient\"/> instance.</param>\n+        /// <param name=\"moduleBuilder\"><see cref=\"ModuleBuilder\"/> to define type in.</param>\n+        /// <param name=\"exceptionTelemetryCtor\"><see cref=\"ConstructorInfo\"/> of default constructor of <see cref=\"ExceptionTelemetry\"/>.</param>\n+        /// <param name=\"trackExceptionMethod\"><see cref=\"MethodInfo\"/> of <see cref=\"TelemetryClient.TrackException(ExceptionTelemetry)\"/>.</param>\n+        private static void AddWebApiExceptionLogger(\n+            TelemetryClient telemetryClient,\n+            ModuleBuilder moduleBuilder,\n+            ConstructorInfo exceptionTelemetryCtor,\n+            MethodInfo trackExceptionMethod)\n+        {\n+            // This method emits following code:\n+            // public class WebApiExceptionLogger : ExceptionLogger\n+            // {\n+            //     public const bool IsAutoInjected = true;\n+            //     private readonly TelemetryClient telemetryClient = new TelemetryClient();\n+            //     \n+            //     public WebApiExceptionLogger(TelemetryClient tc) : base()\n+            //     {\n+            //         telemetryClient = tc;\n+            //     }\n+            //     \n+            //     public override void OnLog(ExceptionLoggerContext context)\n+            //     {\n+            //        if (context != null && context.Exception != null)\n+            //            telemetryClient.TrackException(new ExceptionTelemetry(context.Exception));\n+            //        base.OnLog(context);\n+            //     }\n+            // }\n+            // \n+            // GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger), new WebApiExceptionFilter(new TelemetryClient()));\n+            try\n+            {\n+                // try to get all types/methods/properties/fields\n+                // and if something is not available, fail fast\n+                var baseExceptionLoggerType = GetTypeOrFail(\"System.Web.Http.ExceptionHandling.ExceptionLogger, System.Web.Http\");\n+                if (baseExceptionLoggerType.Assembly.GetName().Version.Major < MinimumWebApiVersion)\n+                {\n+                    WebEventSource.Log.InjectionVersionNotSupported(baseExceptionLoggerType.Assembly.GetName().Version.ToString(), \"WebApi\");\n+                    return;\n+                }\n+\n+                var exceptionContextType = GetTypeOrFail(\"System.Web.Http.ExceptionHandling.ExceptionLoggerContext, System.Web.Http\");\n+                var iexceptionLoggerType = GetTypeOrFail(\"System.Web.Http.ExceptionHandling.IExceptionLogger, System.Web.Http\");\n+\n+                // get GlobalConfiguration.Configuration.Services\n+                GetServicesContainerWebApiOrFail(out dynamic servicesContainer, out Type servicesContainerType);\n+                if (!NeedToInjectWebApi(servicesContainer, servicesContainerType, iexceptionLoggerType))\n+                {\n+                    return;\n+                }\n+\n+                var baseOnLog = GetMethodOrFail(baseExceptionLoggerType, \"Log\", new[] { exceptionContextType });\n+                var addLogger = GetMethodOrFail(servicesContainerType, \"Add\", new[] { typeof(Type), typeof(object) });\n+                var exceptionGetter = GetMethodOrFail(exceptionContextType, \"get_Exception\");\n+                var exceptionLoggerBaseCtor = baseExceptionLoggerType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, CallingConventions.Standard, new Type[0], null);\n+                if (exceptionLoggerBaseCtor == null)\n+                {\n+                    throw new ResolutionException(string.Format(CultureInfo.InvariantCulture, \"Failed to get default constructor for type {0}\", baseExceptionLoggerType.AssemblyQualifiedName));\n+                }\n+\n+                // define 'public class WebApiExceptionLogger : ExceptionLogger' type\n+                TypeBuilder typeBuilder = moduleBuilder.DefineType(WebApiHandlerName, TypeAttributes.Public | TypeAttributes.Class, baseExceptionLoggerType);\n+                DefineAutoInjectedField(typeBuilder);\n+                var telemetryClientField = typeBuilder.DefineField(TelemetryClientFieldName, typeof(TelemetryClient), FieldAttributes.Private | FieldAttributes.InitOnly);\n+\n+                // emit constructor that assigns telemetry client field\n+                EmitConstructor(typeBuilder, typeof(TelemetryClient), telemetryClientField, exceptionLoggerBaseCtor);\n+\n+                // emit Log method \n+                EmitWebApiLog(typeBuilder, exceptionContextType, exceptionGetter, telemetryClientField, exceptionTelemetryCtor, trackExceptionMethod, baseOnLog);\n+\n+                // create error WebApiExceptionLogger type\n+                var exceptionLoggerType = typeBuilder.CreateType();\n+\n+                // add WebApiExceptionLogger to list of services\n+                var exceptionLogger = Activator.CreateInstance(exceptionLoggerType, telemetryClient);\n+                addLogger.Invoke(servicesContainer, new[] { iexceptionLoggerType, exceptionLogger });\n+            }\n+            catch (ResolutionException e)\n+            {\n+                // some of the required types/methods/properties/etc were not found.\n+                // it may indicate we are dealing with a new version of WebApi library\n+                // handle it and log here, we may still succeed with MVC injection\n+                WebEventSource.Log.InjectionFailed(\"WebApi\", e.ToInvariantString());\n+            }\n+        }\n+\n+        /// <summary>\n+        /// Emits OnLog method.\n+        /// </summary>\n+        /// <param name=\"typeBuilder\">MVCExceptionFilter type builder.</param>\n+        /// <param name=\"exceptionContextType\">Type of ExceptionContext.</param>\n+        /// <param name=\"exceptionGetter\">MethodInfo to get ExceptionLoggerContext.Exception.</param>\n+        /// <param name=\"telemetryClientField\">FieldInfo of WebAPIExceptionFilter.telemetryClient.</param>\n+        /// <param name=\"exceptionTelemetryCtor\">ConstructorInfo of ExceptionTelemetry.</param>\n+        /// <param name=\"trackException\">MethodInfo of TelemetryClient.TrackException(ExceptionTelemetry).</param>\n+        /// <param name=\"baseOnLog\">MethodInfo of base (ExceptionLogger) OnLog method.</param>\n+        private static void EmitWebApiLog(TypeBuilder typeBuilder, Type exceptionContextType, MethodInfo exceptionGetter, FieldInfo telemetryClientField, ConstructorInfo exceptionTelemetryCtor, MethodInfo trackException, MethodInfo baseOnLog)\n+        {\n+            // This method emits following code:\n+            // public override void OnLog(ExceptionLoggerContext context)\n+            // {\n+            //    if (context != null && context.Exception != null)\n+            //        telemetryClient.TrackException(new ExceptionTelemetry(context.Exception));\n+            //    base.OnLog(context);\n+            // }\n+            // public override void OnLog(ExceptionLoggerContext context)","path":"Src/Web/Web.Shared.Net/Implementation/ExceptionHandlersInjector.cs","position":467,"original_position":467,"commit_id":"717880014bb08b6c9022f3758734f6534786102a","original_commit_id":"717880014bb08b6c9022f3758734f6534786102a","user":{"login":"lmolkova","id":2347409,"avatar_url":"https://avatars2.githubusercontent.com/u/2347409?v=4","gravatar_id":"","url":"https://api.github.com/users/lmolkova","html_url":"https://github.com/lmolkova","followers_url":"https://api.github.com/users/lmolkova/followers","following_url":"https://api.github.com/users/lmolkova/following{/other_user}","gists_url":"https://api.github.com/users/lmolkova/gists{/gist_id}","starred_url":"https://api.github.com/users/lmolkova/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lmolkova/subscriptions","organizations_url":"https://api.github.com/users/lmolkova/orgs","repos_url":"https://api.github.com/users/lmolkova/repos","events_url":"https://api.github.com/users/lmolkova/events{/privacy}","received_events_url":"https://api.github.com/users/lmolkova/received_events","type":"User","site_admin":false},"body":"Precompiled assemble must still be compiled with some specific version on MVC/WebApi. \r\nTo avoid binding redirects and assembly resolution issues, we considered an option here to use `AppDomain.CurrentDomain.AssemblyResolve` handler to manually resolve assembly versions when it's not possible automatically.\r\nwe preferred IL injection approach because\r\n1. such event fires for dlls MVC/WebApi depend on. And while public API surface is stable, particular dll dependencies might change: i.e. new dependency is introduced in MVC v6.\r\n2. it is more invasive and may potentially conflict with other components doing the same.\r\n3. while IL injection is harder to maintain, the thing we are doing here is small and simple and does not seem to be changed in future.\r\n\r\nIf we'd need to write more complicated logic, i'd say we should change it `AppDomain.CurrentDomain.AssemblyResolve` approach.","created_at":"2018-03-08T17:40:44Z","updated_at":"2018-03-08T17:40:44Z","html_url":"https://github.com/Microsoft/ApplicationInsights-dotnet-server/pull/847#discussion_r173234494","pull_request_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/pulls/847","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/pulls/comments/173234494"},"html":{"href":"https://github.com/Microsoft/ApplicationInsights-dotnet-server/pull/847#discussion_r173234494"},"pull_request":{"href":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/pulls/847"}},"in_reply_to_id":173025325},"pull_request":{"url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/pulls/847","id":173544286,"html_url":"https://github.com/Microsoft/ApplicationInsights-dotnet-server/pull/847","diff_url":"https://github.com/Microsoft/ApplicationInsights-dotnet-server/pull/847.diff","patch_url":"https://github.com/Microsoft/ApplicationInsights-dotnet-server/pull/847.patch","issue_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/issues/847","number":847,"state":"open","locked":false,"title":"Automates MVC and WebApi exception handling","user":{"login":"lmolkova","id":2347409,"avatar_url":"https://avatars2.githubusercontent.com/u/2347409?v=4","gravatar_id":"","url":"https://api.github.com/users/lmolkova","html_url":"https://github.com/lmolkova","followers_url":"https://api.github.com/users/lmolkova/followers","following_url":"https://api.github.com/users/lmolkova/following{/other_user}","gists_url":"https://api.github.com/users/lmolkova/gists{/gist_id}","starred_url":"https://api.github.com/users/lmolkova/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lmolkova/subscriptions","organizations_url":"https://api.github.com/users/lmolkova/orgs","repos_url":"https://api.github.com/users/lmolkova/repos","events_url":"https://api.github.com/users/lmolkova/events{/privacy}","received_events_url":"https://api.github.com/users/lmolkova/received_events","type":"User","site_admin":false},"body":"This change automates MVC error handler and WebApi exception logger injection.\r\n \r\nNow, we ask customers to do it manually as per this article: https://docs.microsoft.com/en-us/azure/application-insights/app-insights-asp-net-exceptions. VS 'Add AplicationInsights' wizard also adds MVC filter.\r\n\r\nIt allows tracking semi-unhandled exceptions - for requests resulted in 500 in the typical and default production case when custom errors handling was enabled.\r\n\r\nThis helps to onboard SnapshotDebugger customers ensuring important exceptions are tracked and in general, improves error detection for all AppInsights ASP.NET customers hosting their apps on IIS>\r\n\r\nThis change supports only WebAPI 2 and MVC4 (Microsoft.AspNet.Mvc/WebApi nuget version 5).\r\nEarlier versions are not supported since ASP.NET nuget v5 was released in 2013 and is first to target .NET 4.5. (ASP.NET v4 targets .NET 4.0)\r\n\r\nThis change is done through the reflection-based dynamic code generation to prevent AI Web SDK dependency on MVC and WebApi dlls. If such dependency is introduced, it creates difficulties with binding redirects that are unresolvable with SDK light-up.\r\n\r\nThis reflection-based solution implements fail-fast approach - if some type is not resolved, it silently stops preventing further injection. \r\n\r\nAll type generation and injection are done at app startup (when ExceptionTrackingTelemetryModule is initialized) therefore performance impact on requests after service warms up remains intact.\r\nGeneration and injection time remains within reasonable few milliseconds range.\r\n\r\n- [x] I ran Unit Tests locally.\r\n\r\nFor significant contributions please make sure you have completed the following items:\r\n\r\n- [ ] Changes in public surface reviewed \r\n**the new property is introduced**:\r\n`ExceptionTrackingTelemetryModule EnableMvcAndWebApiExceptionAutoTracking` to disable injection through the config\r\n\r\n- [x] Design discussion issue - discussed over emails/meetings with @SergeyKanzhelev  and @zakimaksyutov \r\n- [x] CHANGELOG.md updated with one line description of the fix, and a link to the original issue.\r\n","created_at":"2018-03-07T19:02:46Z","updated_at":"2018-03-08T17:40:44Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4dc9e3c4a8e1acc9cc97dd77bad2476912ff1849","assignee":{"login":"lmolkova","id":2347409,"avatar_url":"https://avatars2.githubusercontent.com/u/2347409?v=4","gravatar_id":"","url":"https://api.github.com/users/lmolkova","html_url":"https://github.com/lmolkova","followers_url":"https://api.github.com/users/lmolkova/followers","following_url":"https://api.github.com/users/lmolkova/following{/other_user}","gists_url":"https://api.github.com/users/lmolkova/gists{/gist_id}","starred_url":"https://api.github.com/users/lmolkova/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lmolkova/subscriptions","organizations_url":"https://api.github.com/users/lmolkova/orgs","repos_url":"https://api.github.com/users/lmolkova/repos","events_url":"https://api.github.com/users/lmolkova/events{/privacy}","received_events_url":"https://api.github.com/users/lmolkova/received_events","type":"User","site_admin":false},"assignees":[{"login":"lmolkova","id":2347409,"avatar_url":"https://avatars2.githubusercontent.com/u/2347409?v=4","gravatar_id":"","url":"https://api.github.com/users/lmolkova","html_url":"https://github.com/lmolkova","followers_url":"https://api.github.com/users/lmolkova/followers","following_url":"https://api.github.com/users/lmolkova/following{/other_user}","gists_url":"https://api.github.com/users/lmolkova/gists{/gist_id}","starred_url":"https://api.github.com/users/lmolkova/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lmolkova/subscriptions","organizations_url":"https://api.github.com/users/lmolkova/orgs","repos_url":"https://api.github.com/users/lmolkova/repos","events_url":"https://api.github.com/users/lmolkova/events{/privacy}","received_events_url":"https://api.github.com/users/lmolkova/received_events","type":"User","site_admin":false}],"requested_reviewers":[{"login":"cijothomas","id":5232798,"avatar_url":"https://avatars3.githubusercontent.com/u/5232798?v=4","gravatar_id":"","url":"https://api.github.com/users/cijothomas","html_url":"https://github.com/cijothomas","followers_url":"https://api.github.com/users/cijothomas/followers","following_url":"https://api.github.com/users/cijothomas/following{/other_user}","gists_url":"https://api.github.com/users/cijothomas/gists{/gist_id}","starred_url":"https://api.github.com/users/cijothomas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cijothomas/subscriptions","organizations_url":"https://api.github.com/users/cijothomas/orgs","repos_url":"https://api.github.com/users/cijothomas/repos","events_url":"https://api.github.com/users/cijothomas/events{/privacy}","received_events_url":"https://api.github.com/users/cijothomas/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/pulls/847/commits","review_comments_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/pulls/847/comments","review_comment_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/issues/847/comments","statuses_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/statuses/717880014bb08b6c9022f3758734f6534786102a","head":{"label":"Microsoft:lmolkova/ExceptionHandling","ref":"lmolkova/ExceptionHandling","sha":"717880014bb08b6c9022f3758734f6534786102a","user":{"login":"Microsoft","id":6154722,"avatar_url":"https://avatars2.githubusercontent.com/u/6154722?v=4","gravatar_id":"","url":"https://api.github.com/users/Microsoft","html_url":"https://github.com/Microsoft","followers_url":"https://api.github.com/users/Microsoft/followers","following_url":"https://api.github.com/users/Microsoft/following{/other_user}","gists_url":"https://api.github.com/users/Microsoft/gists{/gist_id}","starred_url":"https://api.github.com/users/Microsoft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Microsoft/subscriptions","organizations_url":"https://api.github.com/users/Microsoft/orgs","repos_url":"https://api.github.com/users/Microsoft/repos","events_url":"https://api.github.com/users/Microsoft/events{/privacy}","received_events_url":"https://api.github.com/users/Microsoft/received_events","type":"Organization","site_admin":false},"repo":{"id":44223665,"name":"ApplicationInsights-dotnet-server","full_name":"Microsoft/ApplicationInsights-dotnet-server","owner":{"login":"Microsoft","id":6154722,"avatar_url":"https://avatars2.githubusercontent.com/u/6154722?v=4","gravatar_id":"","url":"https://api.github.com/users/Microsoft","html_url":"https://github.com/Microsoft","followers_url":"https://api.github.com/users/Microsoft/followers","following_url":"https://api.github.com/users/Microsoft/following{/other_user}","gists_url":"https://api.github.com/users/Microsoft/gists{/gist_id}","starred_url":"https://api.github.com/users/Microsoft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Microsoft/subscriptions","organizations_url":"https://api.github.com/users/Microsoft/orgs","repos_url":"https://api.github.com/users/Microsoft/repos","events_url":"https://api.github.com/users/Microsoft/events{/privacy}","received_events_url":"https://api.github.com/users/Microsoft/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Microsoft/ApplicationInsights-dotnet-server","description":"Microsoft Application Insights for .NET Web Applications","fork":false,"url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server","forks_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/forks","keys_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/teams","hooks_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/hooks","issue_events_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/issues/events{/number}","events_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/events","assignees_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/assignees{/user}","branches_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/branches{/branch}","tags_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/tags","blobs_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/git/refs{/sha}","trees_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/statuses/{sha}","languages_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/languages","stargazers_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/stargazers","contributors_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/contributors","subscribers_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/subscribers","subscription_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/subscription","commits_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/commits{/sha}","git_commits_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/git/commits{/sha}","comments_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/comments{/number}","issue_comment_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/issues/comments{/number}","contents_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/contents/{+path}","compare_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/merges","archive_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/downloads","issues_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/issues{/number}","pulls_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/pulls{/number}","milestones_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/milestones{/number}","notifications_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/labels{/name}","releases_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/releases{/id}","deployments_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/deployments","created_at":"2015-10-14T04:20:22Z","updated_at":"2018-03-04T21:07:32Z","pushed_at":"2018-03-08T07:58:54Z","git_url":"git://github.com/Microsoft/ApplicationInsights-dotnet-server.git","ssh_url":"git@github.com:Microsoft/ApplicationInsights-dotnet-server.git","clone_url":"https://github.com/Microsoft/ApplicationInsights-dotnet-server.git","svn_url":"https://github.com/Microsoft/ApplicationInsights-dotnet-server","homepage":"https://azure.microsoft.com/services/application-insights/","size":56556,"stargazers_count":71,"watchers_count":71,"language":"C#","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":49,"mirror_url":null,"archived":false,"open_issues_count":101,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit"},"forks":49,"open_issues":101,"watchers":71,"default_branch":"develop"}},"base":{"label":"Microsoft:develop","ref":"develop","sha":"aa658aaa7ece00701446e66747a078b930199a62","user":{"login":"Microsoft","id":6154722,"avatar_url":"https://avatars2.githubusercontent.com/u/6154722?v=4","gravatar_id":"","url":"https://api.github.com/users/Microsoft","html_url":"https://github.com/Microsoft","followers_url":"https://api.github.com/users/Microsoft/followers","following_url":"https://api.github.com/users/Microsoft/following{/other_user}","gists_url":"https://api.github.com/users/Microsoft/gists{/gist_id}","starred_url":"https://api.github.com/users/Microsoft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Microsoft/subscriptions","organizations_url":"https://api.github.com/users/Microsoft/orgs","repos_url":"https://api.github.com/users/Microsoft/repos","events_url":"https://api.github.com/users/Microsoft/events{/privacy}","received_events_url":"https://api.github.com/users/Microsoft/received_events","type":"Organization","site_admin":false},"repo":{"id":44223665,"name":"ApplicationInsights-dotnet-server","full_name":"Microsoft/ApplicationInsights-dotnet-server","owner":{"login":"Microsoft","id":6154722,"avatar_url":"https://avatars2.githubusercontent.com/u/6154722?v=4","gravatar_id":"","url":"https://api.github.com/users/Microsoft","html_url":"https://github.com/Microsoft","followers_url":"https://api.github.com/users/Microsoft/followers","following_url":"https://api.github.com/users/Microsoft/following{/other_user}","gists_url":"https://api.github.com/users/Microsoft/gists{/gist_id}","starred_url":"https://api.github.com/users/Microsoft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Microsoft/subscriptions","organizations_url":"https://api.github.com/users/Microsoft/orgs","repos_url":"https://api.github.com/users/Microsoft/repos","events_url":"https://api.github.com/users/Microsoft/events{/privacy}","received_events_url":"https://api.github.com/users/Microsoft/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Microsoft/ApplicationInsights-dotnet-server","description":"Microsoft Application Insights for .NET Web Applications","fork":false,"url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server","forks_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/forks","keys_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/teams","hooks_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/hooks","issue_events_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/issues/events{/number}","events_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/events","assignees_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/assignees{/user}","branches_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/branches{/branch}","tags_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/tags","blobs_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/git/refs{/sha}","trees_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/statuses/{sha}","languages_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/languages","stargazers_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/stargazers","contributors_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/contributors","subscribers_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/subscribers","subscription_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/subscription","commits_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/commits{/sha}","git_commits_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/git/commits{/sha}","comments_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/comments{/number}","issue_comment_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/issues/comments{/number}","contents_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/contents/{+path}","compare_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/merges","archive_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/downloads","issues_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/issues{/number}","pulls_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/pulls{/number}","milestones_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/milestones{/number}","notifications_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/labels{/name}","releases_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/releases{/id}","deployments_url":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/deployments","created_at":"2015-10-14T04:20:22Z","updated_at":"2018-03-04T21:07:32Z","pushed_at":"2018-03-08T07:58:54Z","git_url":"git://github.com/Microsoft/ApplicationInsights-dotnet-server.git","ssh_url":"git@github.com:Microsoft/ApplicationInsights-dotnet-server.git","clone_url":"https://github.com/Microsoft/ApplicationInsights-dotnet-server.git","svn_url":"https://github.com/Microsoft/ApplicationInsights-dotnet-server","homepage":"https://azure.microsoft.com/services/application-insights/","size":56556,"stargazers_count":71,"watchers_count":71,"language":"C#","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":49,"mirror_url":null,"archived":false,"open_issues_count":101,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit"},"forks":49,"open_issues":101,"watchers":71,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/pulls/847"},"html":{"href":"https://github.com/Microsoft/ApplicationInsights-dotnet-server/pull/847"},"issue":{"href":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/issues/847"},"comments":{"href":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/issues/847/comments"},"review_comments":{"href":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/pulls/847/comments"},"review_comment":{"href":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/pulls/847/commits"},"statuses":{"href":"https://api.github.com/repos/Microsoft/ApplicationInsights-dotnet-server/statuses/717880014bb08b6c9022f3758734f6534786102a"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"lmolkova"}}