解决WCF不能直接序列化SqlParameter类型的问题

为了解决WCF不能直接序列化 SqlParameter 类型的问题,可以采用以下步骤:

1. 自定义 DataContractResolver

SqlParameter 类型不能被WCF直接序列化,需要自定义 DataContractResolver 以解决该问题。在自定义 DataContractResolver 的过程中,需要使用一些类来处理实际的序列化和反序列化操作。

首先,定义两个辅助类 SqlParameterSurrogateSqlParameterSurrogateSelector。前者用于存储 SqlParameter 的信息,后者用于选择当前类型是否要使用自定义的序列化方式。

[DataContract]
public class SqlParameterSurrogate
{
    [DataMember]
    public string ParameterName { get; set; }

    [DataMember]
    public ParameterDirection Direction { get; set; }

    [DataMember]
    public SqlDbType SqlDbType { get; set; }

    [DataMember]
    public object Value { get; set; }

    [DataMember]
    public int Size { get; set; }
}

public class SqlParameterSurrogateSelector : IDataContractSurrogate
{
    public bool CanSerialize(Type type, Type surrogateType)
    {
        return type == typeof(SqlParameter);
    }

    public object GetCustomDataToExport(Type clrType, Type dataContractType)
    {
        return null;
    }

    public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
    {
        return null;
    }

    public Type GetDataContractType(Type type)
    {
        return typeof(SqlParameterSurrogate);
    }

    public object GetDeserializedObject(object obj, Type targetType)
    {
        var surrogate = (SqlParameterSurrogate)obj;
        var parameter = new SqlParameter
        {
            ParameterName = surrogate.ParameterName,
            SqlDbType = surrogate.SqlDbType,
            Value = surrogate.Value,
            Direction = surrogate.Direction
        };
        if (surrogate.Size > 0)
        {
            parameter.Size = surrogate.Size;
        }

        return parameter;
    }

    public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
    {
    }

    public object GetObjectToSerialize(object obj, Type targetType)
    {
        var parameter = (SqlParameter)obj;
        return new SqlParameterSurrogate
        {
            ParameterName = parameter.ParameterName,
            SqlDbType = parameter.SqlDbType,
            Value = parameter.Value,
            Direction = parameter.Direction,
            Size = parameter.Size
        };
    }

    public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
    {
        return typeof(SqlParameterSurrogate);
    }

    public void ImportCallback(System.Runtime.Serialization.XmlObjectSerializer serializer, object deserializedObject)
    {
    }

    public void ProcessDataContractSurrogate(Type clrType, Type dataContractType, IDataContractSurrogateContext context)
    {
        context.DataContractSurrogate = this;
    }

    public object SetAndValidateUnknownAttribute(string name, string ns, object value, SerializationInfo info)
    {
        return null;
    }

    public bool ShouldSerialize(Type type, object obj)
    {
        return true;
    }
}

上述代码中,SqlParameterSurrogate 用于存储 SqlParameter 的信息,包括 ParameterNameDirectionSqlDbTypeValueSize 这五个属性。SqlParameterSurrogateSelector 则用于选择 SqlParameter 类型是否要使用自定义的序列化方式。可以看到,当序列化过程中遇到 SqlParameter 类型时,GetDataContractType 方法会返回 SqlParameterSurrogate 类型,GetObjectToSerialize 方法会将 SqlParameter 对象序列化成 SqlParameterSurrogate 对象。当反序列化过程中遇到 SqlParameterSurrogate 类型时,GetDeserializedObject 方法会将 SqlParameterSurrogate 对象反序列化成 SqlParameter 对象。

2. 配置 DataContractSerializer

经过以上自定义 DataContractResolver 的操作,我们需要将其应用于 WCF 的 DataContractSerializer 中以实现 SqlParameter 对象的序列化与反序列化,可以参考以下步骤:

var serializer = new DataContractSerializer(typeof(RequestMessage), new Type[] { typeof(SqlParameter) });
serializer.SetSerializationSurrogateProvider(new MySerializationSurrogateProvider());

在以上代码中:

  • RequestMessage 是自定义的消息类型,这里只是作为一个示例。
  • MySerializationSurrogateProvider 是自定义的 IDataContractSurrogateProvider 类型,用于提供 SqlParameterSurrogateSelector 对象。

示例1

具体来说,对于下面的WCF服务,如果存在存储过程 CreateOrder,那么我需要先将订单信息存到数据库。代码如下:

[ServiceContract]
public interface IOrderService
{
    [OperationContract]
    void CreateOrder(Order order);
}

public class Order
{
    public int Id { get; set; }
    public string CustomerName { get; set; }
    public decimal Price { get; set; }
    public SqlParameter[] Parameters { get; set; }
}

public class OrderService : IOrderService
{
    public void CreateOrder(Order order)
    {
        const string connectionString = "Data Source=(local);Initial Catalog=Test;Integrated Security=True;";
        using (var connection = new SqlConnection(connectionString))
        {
            connection.Open();
            var command = new SqlCommand("CreateOrder", connection)
            {
                CommandType = CommandType.StoredProcedure,
                CommandTimeout = 300
            };
            command.Parameters.Add(new SqlParameter("@CustomerName", SqlDbType.NVarChar, 50)).Value = order.CustomerName;
            command.Parameters.Add(new SqlParameter("@Price", SqlDbType.Decimal, 18)).Value = order.Price;
            foreach (var parameter in order.Parameters)
            {
                command.Parameters.Add(parameter);
            }
            command.ExecuteNonQuery();
        }
    }
}

可以看到,Order 类中包含了一个 SqlParameter[] 类型的属性,但是 WCF 默认情况下不能对该类型进行序列化。因此,我们需要按照上文所述实现自定义解决方案。修改客户端程序如下:

using (var client = new OrderServiceClient())
{
    client.Open();
    client.CreateOrder(new Order
    {
        CustomerName = "CustomerA",
        Price = 100,
        Parameters = new SqlParameter[]
        {
            new SqlParameter("@Notes", SqlDbType.NVarChar, 200).Value = "新订单",
            new SqlParameter("@IsUrgent", SqlDbType.Bit).Value = true
        }
    });
}

构造 Order 对象时,我们可以为其中的 SqlParameter[] 属性添加一些测试数据。

示例2

此外,我们还可以以 DataSet 或 DataTable 对象形式传递 SqlParameter 类型的参数,构造存储过程的测试代码如下:

public void CreateOrder(DataSet dataSet)
{
    const string connectionString = "Data Source=(local);Initial Catalog=Test;Integrated Security=True;";
    using (var connection = new SqlConnection(connectionString))
    {
        connection.Open();
        var command = new SqlCommand("CreateOrderFromDataTable", connection)
        {
            CommandType = CommandType.StoredProcedure,
            CommandTimeout = 300
        };
        command.Parameters.Add("@orders", SqlDbType.Structured);
        command.Parameters["@orders"].Value = dataSet.Tables[0];
        command.ExecuteNonQuery();
    }
}

可以看到,在构造存储过程的 SqlCommand 对象时,我们为 @orders 参数指定了类型为 SqlDbType.Structured,因此我们需要将数据以 DataTable 或 DataSet 的形式传递。修改客户端程序如下:

using (var client = new OrderServiceClient())
{
    client.Open();
    var dataSet = new DataSet();
    var dataTable = dataSet.Tables.Add("OrderTable");
    dataTable.Columns.Add("OrderId", typeof(int));
    dataTable.Columns.Add("CustomerName", typeof(string));
    dataTable.Columns.Add("OrderDate", typeof(DateTime));
    dataTable.Rows.Add(1, "CustomerA", DateTime.Now);
    client.CreateOrder(dataSet);
}

在构造 DataTable 时,需要注意表结构的匹配。经过以上修改,就可以在 WCF 中直接使用 SqlParameter 类型的参数了。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:解决WCF不能直接序列化SqlParameter类型的问题 - Python技术站

(0)
上一篇 2023年5月15日
下一篇 2023年5月15日

相关文章

  • C#使用foreach语句搜索数组元素的方法

    当我们需要搜索一个数组中的元素时,可以使用C#中的foreach语句来实现。以下是使用foreach语句搜索数组元素的步骤: 1. 创建一个数组 在开始搜索数组元素之前,需要先创建一个数组,并向其中添加元素。例如,我们要创建一个包含数字1到5的数组,可以使用以下代码: int[] numArray = new int[] {1, 2, 3, 4, 5}; 2…

    C# 2023年6月8日
    00
  • C#Web应用程序入门经典学习笔记之二

    让我来详细讲解一下这篇文章的完整攻略。 一、前言 在这篇文章中,我们将学习如何使用C#语言开发Web应用程序。我们将讲解如何使用ASP.NET框架,以及如何使用Visual Studio来创建和调试Web应用程序。我们还将讲解一些常见的Web开发概念和技术,例如HTML、CSS、JavaScript、MVC等。 二、准备工作 在开始学习C# Web开发之前,…

    C# 2023年5月15日
    00
  • Asp.net Core项目配置HTTPS支持

    下面是Asp.net Core项目配置HTTPS支持的完整攻略。 配置HTTPS支持 在项目中安装Microsoft.AspNetCore.HttpsPolicy包 PM> Install-Package Microsoft.AspNetCore.HttpsPolicy 修改ConfigureServices方法,在其中添加使用HttpsRedirec…

    C# 2023年6月3日
    00
  • asp.net 关于==?:和if()else()条件判断等效例子

    ASP.NET 是一种基于 .NET Framework 的 Web 应用程序开发框架,它支持 C#、VB.NET、JScript.NET 和其他高级编程语言。在 ASP.NET 中,我们经常会用到条件判断语句,其中 “==?:” 是常用的一个运算符,而if…else…则是最常见的条件判断语句之一。 1. “==?:”运算符 “==?:” 意思是在判…

    C# 2023年5月31日
    00
  • ASP.NET中下载文件的几种实例代码

    ASP.NET中下载文件的几种实例代码可以分为以下几种: 方法1:使用Response对象下载文件 使用Response对象下载文件是最简单和直接的方式,可以在服务器端使用C#代码将文件发送到客户端。 protected void btnDownload_Click(object sender, EventArgs e) { string filePath …

    C# 2023年5月31日
    00
  • jQuery实现的AJAX简单弹出层效果代码

    jQuery是一种流行的JavaScript库,它提供了许多方便的方法来操作HTML文档、处理事件、执行动画等。其中,jQuery的AJAX功能可以让我们通过异步请求从服务器获取数据,而不必刷新整个页面。本文将提供详解“jQuery实现的AJAX简单弹出层效果代码”的完整攻略,包括如何使用jQuery的AJAX功能、如何使用jQuery实现弹出层效果等。 使…

    C# 2023年5月15日
    00
  • EF Core基础入门教程

    EF Core是一个轻量级的、可扩展的、基于.NET Core的ORM框架,可以让我们更方便地操作数据库。下面的教程将介绍EF Core的基本概念和用法,以及如何使用EF Core在.NET Core应用程序中进行数据持久化。 第一步 安装EF Core 首先,在你的.NET Core项目中,需要通过NuGet安装EF Core相关的包。打开Visual S…

    C# 2023年5月31日
    00
  • 详解ASP.NET配置文件Web.config

    下面是ASP.NET配置文件Web.config的详细讲解攻略: 什么是Web.config文件? Web.config是ASP.NET应用程序的配置文件,用于存储应用程序的配置信息。配置文件定义了应用程序的行为和特性,包括数据库连接、Session状态、HTTP模块、认证和授权等。 Web.config文件结构 Web.config文件的结构如下所示: &…

    C# 2023年6月3日
    00
合作推广
合作推广
分享本页
返回顶部