2016-11-22 5 views
0

Я создал надстройку Outlook с Visual Studio 2013 для Outlook 2010 - 2016. Надстройка Outlook содержит 2 формы WPF, которые используйте REST api и выполняйте HTTP-вызовы. В результате Json и будет десериализован с Newtonsoft Json.Newtonsoft Json используется внутри WPF Форма надстройки Outlook не находит Конфигурация приложения

В режиме отладки все работает нормально. Как только я создаю средство установки с помощью wix и устанавливаю надстройку, у меня возникла проблема с тем, что Json Objects больше не десериализуются. Причина этого заключается в том, что надстройка не находит файл конфигурации. Я понял, что Outlook ищет outlook.exe.config в пути программы Office Outlook. Но это не то, что я хочу, потому что я не хочу делать никаких изменений в этом центральном файле конфигурации, который может повлиять на другие приложения.

После выяснить это, я нашел этот аккуратный маленький фрагмент кода, чтобы изменить конфигурационный файл при запуске моей надстройки:

using System; 
using System.Configuration; 
using System.Linq; 
using System.Reflection; 

public abstract class AppConfig : IDisposable 
{ 
    public static AppConfig Change(string path) 
    { 
     return new ChangeAppConfig(path); 
    } 

    public abstract void Dispose(); 

    private class ChangeAppConfig : AppConfig 
    { 
     private readonly string oldConfig = 
      AppDomain.CurrentDomain.GetData("APP_CONFIG_FILE").ToString(); 

     private bool disposedValue; 

     public ChangeAppConfig(string path) 
     { 
      AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", path); 
      ResetConfigMechanism(); 
     } 

     public override void Dispose() 
     { 
      if (!disposedValue) 
      { 
       AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", oldConfig); 
       ResetConfigMechanism(); 


       disposedValue = true; 
      } 
      GC.SuppressFinalize(this); 
     } 

     private static void ResetConfigMechanism() 
     { 
      typeof(ConfigurationManager) 
       .GetField("s_initState", BindingFlags.NonPublic | 
             BindingFlags.Static) 
       .SetValue(null, 0); 

      typeof(ConfigurationManager) 
       .GetField("s_configSystem", BindingFlags.NonPublic | 
              BindingFlags.Static) 
       .SetValue(null, null); 

      typeof(ConfigurationManager) 
       .Assembly.GetTypes() 
       .Where(x => x.FullName == 
          "System.Configuration.ClientConfigPaths") 
       .First() 
       .GetField("s_current", BindingFlags.NonPublic | 
             BindingFlags.Static) 
       .SetValue(null, null); 
     } 
    } 
} 

После изменения конфигурации приложения на правильный путь, я могу читать все Настройки из файла конфигурации через System.Configuration.ConfgurationManager (я пробовал его во время выполнения после установки версии выпуска и записывал его в поток файлов).

Но все же ... при попытке десериализации JSON в объект Я получаю следующее сообщение об ошибке:

System.IO.FileLoadException: Could not load file or assembly 'Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040) File name: 'Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' at System.Net.Http.Formatting.JsonMediaTypeFormatter..ctor() at System.Net.Http.Formatting.MediaTypeFormatterCollection.CreateDefaultFormatters() at XXXXXXXXXXXXXXXX.<>c__DisplayClass16.b__14(Task`1 task)

=== Pre-bind state information === LOG: DisplayName = Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed (Fully-specified) LOG: Appbase = file:///C:/Program Files/XXXXXXXXX/ LOG: Initial PrivatePath = NULL Calling assembly : System.Net.Http.Formatting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35. === LOG: This bind starts in default load context. LOG: No application configuration file found. LOG: Using host configuration file: LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config. LOG: Post-policy reference: Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed LOG: Attempting download of new URL file:///C:/Program Files/XXXXXX/Newtonsoft.Json.DLL. WRN: Comparing the assembly name resulted in the mismatch: Major Version ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.

Это, как выглядит мой файл app.config, как:

<?xml version="1.0" encoding="utf-8"?>> 
 
<configuration> 
 
    <appSettings> 
 
    <add key="ApiUrl" value="http://localhost:56610/api" /> 
 
    </appSettings> 
 
    <runtime> 
 
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
 
     <dependentAssembly> 
 
     <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" /> 
 
     <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" /> 
 
     </dependentAssembly> 
 
    </assemblyBinding> 
 
    </runtime> 
 
</configuration>

Кто-нибудь знает, почему конфигурация Newtonsoft Json не работает и почему конфигурация, которую я предоставил, не используется?

Большое спасибо за помощь.

ответ

0

Я нашел обходное решение для своей проблемы. Мой исходный код был как следующее:

 public DomainUser FindUserBySecurityIdentifier(SecurityIdentifier securityIdentifier) 
    { 
     var domainUser = new DomainUser(securityIdentifier.ToString()); 
     string domainUserJson = Newtonsoft.Json.JsonConvert.SerializeObject(domainUser); 
     HttpContent content = new StringContent(domainUserJson); 
     content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); 
     Exception exception = null; 

     var item = DomainUser.EMPTY; 
     var endpointUrl = ConstructEndpointUrl("api/FindUserBySecurityIdentifier"); 

     if (!string.IsNullOrWhiteSpace(endpointUrl)) 
     { 
      Task postLink = HttpClient.PostAsync(endpointUrl, content).ContinueWith(task => 
      { 
       if (task.Status == TaskStatus.RanToCompletion) 
       { 
        var response = task.Result; 
        if (response.IsSuccessStatusCode) 
        { 
         // The error occured at this line 
         item = response.Content.ReadAsAsync<DomainUser>().Result; 
        } 
        else 
        { 
         exception = new Exception(response.ToString()); 
        } 
       } 
       else 
       { 
        exception = new Exception("The http request to the server did not run to completion. Please contact the administrator"); 
       } 
      }); 
      postLink.Wait(); 
     } 
     if (exception != null) 
     { 
      throw exception; 
     } 
     return item; 
    } 

После того как я изменил код как следующий он, наконец, работает

 public DomainUser FindUserBySecurityIdentifier(SecurityIdentifier securityIdentifier) 
    { 
     var domainUser = new DomainUser(securityIdentifier.ToString()); 
     string domainUserJson = Newtonsoft.Json.JsonConvert.SerializeObject(domainUser); 
     HttpContent content = new StringContent(domainUserJson); 
     content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); 
     Exception exception = null; 

     var item = DomainUser.EMPTY; 
     var endpointUrl = ConstructEndpointUrl("api/FindUserBySecurityIdentifier"); 

     if (!string.IsNullOrWhiteSpace(endpointUrl)) 
     { 
      Task postLink = HttpClient.PostAsync(endpointUrl, content).ContinueWith(task => 
      { 
       if (task.Status == TaskStatus.RanToCompletion) 
       { 
        var response = task.Result; 
        if (response.IsSuccessStatusCode) 
        { 
         // after I read the result into a string first and deserialized it with JsonConvert.DeserializeObject it worked 
         var objectAsString = response.Content.ReadAsStringAsync().Result; 
         item = JsonConvert.DeserializeObject<DomainUser>(objectAsString); 
        } 
        else 
        { 
         exception = new Exception(response.ToString()); 
        } 
       } 
       else 
       { 
        exception = new Exception("The http request to the server did not run to completion. Please contact the administrator"); 
       } 
      }); 
      postLink.Wait(); 
     } 
     if (exception != null) 
     { 
      throw exception; 
     } 
     return item; 
    }