2016-11-22 44 views
0

我已經爲Outlook 2010-2016創建了Outlook插件與Visual Studio 2013. Outlook加載項包含2個WPF表單利用REST api並執行http休息調用。結果是Json,並且會被Newtonsoft Json反序列化。內部使用的Outlook插件的WPF窗體中使用的Newtonsoft Json未找到應用程序配置

在調試模式下,一切正常。 只要我用wix創建安裝工具並安裝加載項,我就得到了Json對象不再被反序列化的問題。原因是加載項沒有找到配置文件。 我發現Outlook在Office Outlook程序路徑中查找了outlook.exe.config。但這不是我想要的,因爲我不想在可能影響其他應用程序的中央配置文件中進行任何更改。

搞清楚這之後,我發現這個整潔的小代碼段來更改配置文件在我的加載的啓動:

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; 
    } 
以下
相關問題