簡體   English   中英

互操作程序集中使用的 BinaryFormatter 引發 UnsupportedException

[英]BinaryFormatter used in Interop assemblies throws UnsupportedException

Microsoft 不鼓勵使用BinaryFormatter ,因為它會帶來安全問題。 請參閱: BinaryFormatter 廢棄策略

我有一個使用Microsoft.Office.Interop.Access.Dao互操作程序集的 .NET 6.0 WinForms 代碼。 我需要它將圖像插入 Microsoft Access 系統表MSysResourcesData字段中。 該字段具有Attachment數據類型。 這是一個多值字段。 使用 DAO 是寫入該字段的唯一方法。 我的(有些縮短的)代碼是這樣的(注意:在我遷移到 .NET 6.0 之前,此代碼確實有效):

using Microsoft.Office.Interop.Access.Dao;

namespace CySoft.RibbonPro.Services;

public class AccessImageResourceLoader : IAccessImageResourceLoader
{
    public void UpdateImages(string accdbFile, IEnumerable<KeyValuePair<string, Image>> images)
    {
        var dbe = new DBEngine(); // <====== This line throws the UnsupportedException =====

        Database db = dbe.OpenDatabase(accdbFile);
        Recordset rs = rs = db.OpenRecordset("SELECT * FROM MSysResources WHERE 0=1", R
            ecordsetTypeEnum.dbOpenDynaset, 0, LockTypeEnum.dbOptimistic);
        rs.AddNew();
        rs.Fields["Type"].Value = "img";
        rs.Fields["Name"].Value = name;
        rs.Fields["Extension"].Value = ext;

        Recordset2 rsAttachment = (Recordset2)rs.Fields["Data"].Value;
        rsAttachment.AddNew();
        Field2 dataField = (Field2)rsAttachment.Fields["FileData"];
        dataField.LoadFromFile(imageInfo.Key);
        rsAttachment.Update();

        rs.Update();
        rs.Close();
        db.Close();
    }
}

詳情僅供說明。 創建DBEngine的第一行代碼拋出異常:

BinaryFormatter 序列化已過時,不應使用。 有關詳細信息,請參閱https://aka.ms/binaryformatter

調用棧是:

at System.ComponentModel.Design.DesigntimeLicenseContextSerializer.DeserializeUsingBinaryFormatter(StreamWrapper wrappedStream, String cryptoKey, RuntimeLicenseContext context)
at System.ComponentModel.Design.DesigntimeLicenseContextSerializer.Deserialize(Stream o, String cryptoKey, RuntimeLicenseContext context)
at System.ComponentModel.Design.RuntimeLicenseContext.GetSavedLicenseKey(Type type, Assembly resourceAssembly)
at System.ComponentModel.LicenseManager.LicenseInteropHelper.GetCurrentContextInfo(Type type, Boolean& isDesignTime, String& key)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Internal.Runtime.InteropServices.LicenseInteropProxy.GetCurrentContextInfo(RuntimeTypeHandle rth, Boolean& isDesignTime, IntPtr& bstrKey)
at CySoft.RibbonPro.Services.AccessImageResourceLoader.UpdateImages(String accdbFile, IEnumerable`1 images) in C:\Users\Oli\Documents\Proj\CySoft\CySoft.RibbonPro\CySoft.RibbonPro\Services\AccessImageResourceLoader.cs:line 21

AccessImageResourceLoader.cs:line 21 是var dbe = new DBEngine();

微軟希望人們使用另一種類型的序列化,例如 JSON 或 XML。 在這種情況下,這不是一個選項,因為我沒有直接使用它。 使用它的是微軟自己的 COM 庫。

問題:
如何在 .NET 6+ 中使用 Access 的Attachment數據類型插入或更新記錄?

我的嘗試

  • 我試圖用System.Data.OleDb來做到這一點。 我可以用 OleDb 閱讀附件。 但任何使用 OleDb 寫入該字段的嘗試都會引發異常。

  • 在項目文件中設置<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>標記沒有幫助。

  • runtimeConfig.template.json中設置相同的配置屬性也無濟於事。


我知道我可以通過互操作程序集使用 Access 自動化來解決問題。 但是打開Microsoft Access應用程序有一個缺點。 通過數據庫連接插入圖像要優雅得多,並且在我遷移到 .NET 6.0 之前確實有效。

您可以在這里看到有一個開關允許許可證文件的二進制序列化程序

https://github.com/dotnet/runtime/blob/main/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs#L20

此處的GetSavedLicenseKey方法正在讀取

https://github.com/dotnet/runtime/blob/main/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContext.cs#L84-L89

您可以通過調用以下命令在初始化DBEngine object 之前提前設置此開關:

AppContext.SetSwitch("System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization", true);

我自己沒有嘗試過,但它應該可以工作。

此運行時開關也可以在 csproj 文件中設置,如此處所述

https://github.com/dotnet/runtime/blob/main/docs/workflow/trimming/feature-switches.md

任何定義屬性的功能開關都可以在 csproj 文件或命令行中設置為任何其他 MSBuild 屬性。 那些沒有預定義屬性名稱的值可以在 csproj 文件中使用以下 XML 標簽設置。

<RuntimeHostConfigurationOption Include="<AppContext-Setting>"
                                Value="false"
                                Trim="true" />

最后的話:在這個博客上還有更多關於升級到 .NET 6.0 的詳細信息,其中解釋了這個標志的另一種方法。

https://www.textcontrol.com/blog/2021/12/21/migrate-a-windows-forms-desktop-application-to-dotnet-6/?hmsr=joyk.com&utm_source=joyk.com&utm_medium=referral

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM