属性构造函数所需的常量表达式

问题描述 投票:0回答:1

我正在尝试使用问题中的代码实现加密的 JSON 属性 使用 Json.NET,在序列化我的对象时如何加密任何类型的选定属性?。我最初在我的应用程序中设置了一些“密钥”作为常量 (

Const
),但我最近想到使用另一个更独特的值来应用此加密 - 用户将需要在期间输入的令牌应用程序的初始设置。但是,当我尝试更改为使用该令牌而不是原始密钥时,我遇到了
Constant expression is required
消息。

用于标记 JSON 属性以进行加密的原始工作代码如下所示:

<EditorBrowsable(EditorBrowsableState.Never)>
Private Class MyEndpoint
    <JsonProperty("endpoint")> <JsonEncrypt(EndpointKey)>
    Public Property Endpoint As Endpoint
End Class

<EditorBrowsable(EditorBrowsableState.Never)>
Private Class MyConnectionString
    <JsonProperty("connection_string")> <JsonEncrypt(ConnectionStringKey)>
    Public Property ConnectionString As ConnectionString
End Class

<EditorBrowsable(EditorBrowsableState.Never)>
Private Class MyUserCredential
    <JsonProperty("credentials")> <JsonEncrypt(CredentialKey)>
    Public Property Credential As Credential
End Class

我有这样的

JsonEncryptAttribute
课程:

<AttributeUsage(AttributeTargets.[Property] Or AttributeTargets.Field, AllowMultiple:=False)>
Public NotInheritable Class JsonEncryptAttribute
    Inherits Attribute

    Public Property EncryptionKey As Byte()

    Public Sub New()
        Me.EncryptionKey = GenerateKey(DefaultKey)
    End Sub

    Public Sub New(ByVal Password As String)
        Me.EncryptionKey = GenerateKey(Password)
    End Sub

    Private Function GenerateKey(ByVal Password As String) As Byte()
        Return SHA256.HashData(Encoding.UTF8.GetBytes(Password))
    End Function
End Class

但是,当我将

MyEndpoint
类定义更改为看起来像 this:

<EditorBrowsable(EditorBrowsableState.Never)>
Private Class MyEndpoint
    <JsonProperty("endpoint")> <JsonEncrypt(Settings.AppTokens("myapp"))>
    Public Property Endpoint As Endpoint
End Class

...其中

AppTokens
Settings
类中的一个属性,它将被单独保存和读取,IDE 犹豫并给我
Constant expression is required
消息。基于
JsonEncryptAttribute
类的构造函数,我对 why 一开始就要求值是
Const
完全感到困惑。

但是,查看文档,我认为错误与

AppTokens
(定义为
Dictionary(Of String, String)
)是最有可能的罪魁祸首这一事实有关:

Const
语句没有正确初始化常量,或者数组声明使用变量来指定元素的数量。

错误编号:BC30059

纠正这个错误

如果声明是

Const
语句,请检查以确保使用文字、先前声明的常量、枚举成员或文字、常量和枚举成员与运算符的组合来初始化常量。

如果声明指定了数组,请检查是否使用了变量来指定元素的数量。如果是这样,用常量表达式替换变量。

我看了另一个问题的自我接受的答案 - 枚举属性中的变量:需要常量表达式 - 并尝试实现类似的东西但是,除非我只是做错了(确定的可能性),它似乎不适用于类属性。

<JsonEncrypt(GetType(Settings), NameOf(Settings.AppTokens("myapp")))>

所以,现在我剩下以下问题:

  1. 任何人都可以向我解释为什么这里发生这个错误?跟

    JsonEncryptAttribute
    继承基数
    System.Attribute
    有关系吗?

  2. 有没有办法通过使用不同的对象类型或其他东西来解决这个问题?

    AppTokens
    是从应用程序的“基本”JSON 配置文件中读取的,因此任何替代方案都必须与之兼容。

vb.net variables constructor attributes constants
1个回答
0
投票

我相信我已经找到了一个可行的解决方案,我可以使用令牌作为加密密钥。它只需要对我所拥有的进行一点重构和重组。在阅读了How to set dynamic value in my Attribute之后,我将之前定义为单独的

EndpointKey
字段的
ConnectionStringKey
CredentialKey
Const
值并将它们转换为枚举:

Public Enum ApplicationKeys
    UserToken
    <Description("Default Encryption Key")> DefaultKey
    <Description("Encrypted Setting Key")> Setting
    <Description("Encrypted ConnectionString Key")> ConnectionString
    <Description("Encrypted Endpoint Key")> Endpoint
    <Description("Encrypted Credential Key")> Credential
End Enum

然后,我为

JsonEncryptAttribute
设置了一个新的构造函数,它接受这个枚举作为参数:

Public Sub New(ByVal Key As ApplicationKeys)
    If Key = ApplicationKeys.UserToken Then
        Me.EncryptionKey = GenerateKey(Settings.AppTokens("myapp"))
    Else
        Me.EncryptionKey = GenerateKey(DirectCast([Enum].Parse(GetType(ApplicationKeys), Key), ApplicationKeys).GetDescription)
    End If
End Sub

这使用

GetDescription
扩展方法† 为我可能想使用它们的任何地方提取“预定义”键值,而且如果选择了该枚举,我还可以绘制动态令牌。

显然,我需要在其中添加一些额外的错误处理,以应对标记为

Nothing
或空字符串的可能性,或者如果传递给构造函数的值未定义为
ApplicationKeys
的一部分枚举,但我相信这将提供我真正想要实现的解决方案。


† 只是为了帮助将来可能会看到这个的其他人,这里是

GetDescription
扩展方法:

''' <summary>
''' Gets the Description attribute of an Enum value
''' </summary>
''' <param name="CurrentEnum">The specific Enum value for which to get the Description attribute</param>
''' <returns>String value representing the Description attribute of the specified Enum</returns>
''' <remarks>Requires System.Reflection, System.ComponentModel and System.Runtime.CompilerServices namespaces to be imported.
''' The Description attribute of an Enum is set in the Enum declaration.'</remarks>
<DebuggerStepThrough>
<Extension()>
Public Function GetDescription(ByVal CurrentEnum As [Enum]) As String
    Dim DescAttribute As DescriptionAttribute
    Dim Field As FieldInfo = CurrentEnum.GetType.GetField(CurrentEnum.ToString)

    DescAttribute = DirectCast(Attribute.GetCustomAttribute(Field, GetType(DescriptionAttribute)), DescriptionAttribute)

    If DescAttribute IsNot Nothing Then
        Return DescAttribute.Description
    Else
        Return CurrentEnum.ToString
    End If
End Function
© www.soinside.com 2019 - 2024. All rights reserved.