首頁 > 軟體

解決WCF不能直接序列化SqlParameter型別的問題

2022-03-04 13:02:45

錯誤描述:

由於內部錯誤,伺服器無法處理該請求。有關該錯誤的詳細資訊,請開啟伺服器上的 IncludeExceptionDetailInFaults (從 ServiceBehaviorAttribute 或從 <serviceDebug> 設定行為)以便將異常資訊傳送回使用者端,或開啟對每個 Microsoft .NET Framework SDK 檔案的跟蹤並檢查伺服器跟蹤紀錄檔。

使用者端呼叫WCF的時候報上面的錯誤,WCF只能序列化基礎的資料型別,不能直接序列化SqlParameter型別,需要使用自定義類,然後在WCF伺服器端轉換的方式解決:

自定義類程式碼如下:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;

namespace CommonLib.CustomClass
{
    /// <summary>
    /// 方法標記為DataContract約束,屬性標記為DataMember
    /// </summary>
    [Serializable]
    [DataContract]
    public class SetSqlParameter
    {
        #region 屬性

        /// <summary>
        /// 引數名稱
        /// </summary>
        [DataMember]
        private string paraName = "";
        public string ParaName
        {
            get { return this.paraName; }
            set { this.paraName = value; }

        }


        /// <summary>
        /// 引數長度
        /// </summary>
        [DataMember]
        private int paraLength = 0;
        public int ParaLength
        {

            get { return this.paraLength; }
            set { this.paraLength = value; }
        }


        /// <summary>
        /// 引數值
        /// </summary>
        [DataMember]
        private object paraValue = null;
        public object ParaValue
        {
            get { return this.paraValue; }
            set { this.paraValue = value; }
        }


        /// <summary>
        /// 引數型別
        /// </summary>
        [DataMember]
        private SqlDbType paraDbType = SqlDbType.NVarChar;
        public SqlDbType ParaDbType
        {
            get { return this.paraDbType; }

            set { this.paraDbType = value; }
        }

        #endregion

        /// <summary>
        /// 建構函式
        /// </summary>
        /// <param name="sPara"></param>
        public SetSqlParameter(SqlParameter sPara)
        {
            this.paraName = sPara.ParameterName;
            this.paraLength = sPara.Size;
            this.paraValue = sPara.Value;
            this.paraDbType = sPara.SqlDbType;
        }

        /// <summary>
        /// 轉換成SqlParameter型別
        /// </summary>
        /// <returns></returns>
        public SqlParameter ConvertToSqlParameter()
        {
            SqlParameter parameter = new SqlParameter(this.paraName, this.paraDbType, this.paraLength);
            parameter.Value = this.paraValue;
            return parameter;
        }
    }
}

WCF伺服器端程式碼如下:

介面程式碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using CommonLib.CustomClass;

namespace WcfServiceDemo
{
    // 注意: 使用「重構」選單上的「重新命名」命令,可以同時更改程式碼和組態檔中的介面名「IMyService」。
    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        DataTable ExeceteQuery(string strSQL, params SetSqlParameter[] parameters);
    }
}

介面實現類程式碼:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Configuration;
using CommonLib.CustomClass;

namespace WcfServiceDemo
{
    // 注意: 使用「重構」選單上的「重新命名」命令,可以同時更改程式碼、svc 和組態檔中的類名「MyService」。
    // 注意: 為了啟動 WCF 測試使用者端以測試此服務,請在解決方案資源管理器中選擇 MyService.svc 或 MyService.svc.cs,然後開始偵錯。
    public class MyService : IMyService
    {

        public DataTable ExeceteQuery(string strSQL, params SetSqlParameter[] parameters)
        {
            DataTable dtReturn = new DataTable();
            dtReturn.TableName = "ExecuteQuery";
            string strCon = ConfigurationManager.ConnectionStrings["HealthHospInfection"].ConnectionString;
            using (SqlConnection conn = new SqlConnection(strCon))
            {
                SqlCommand cmd = new SqlCommand(strSQL, conn);
                conn.Open();
                if (parameters != null)
                {
                    SqlParameter[] para = new SqlParameter[parameters.Length];
                    for (int i = 0; i < parameters.Length; i++)
                    {
                        //把SetSqlParameter型別的陣列轉換成SqlParameter型別的陣列
                        para[i] = parameters[i].ConvertToSqlParameter();
                    }
                    cmd.Parameters.AddRange(para);
                }

                SqlDataAdapter adapter = new SqlDataAdapter(cmd);
                adapter.Fill(dtReturn);
            }
            return dtReturn;
        }
    }
}

使用者端呼叫WCF程式碼:

using CommonLib.CustomClass;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace winClient
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btn_GetData_Click(object sender, EventArgs e)
        {

            string strSQL = " SELECT * FROM BaseSetMainInfo WHERE TypeCode=@TypeCode ";

            //定義SqlParameter
            SqlParameter para = new SqlParameter("@TypeCode", SqlDbType.Int);
            para.Value = 1;

            //定義SetSqlParameter型別的陣列
            SetSqlParameter[] paras = new SetSqlParameter[] {
                new SetSqlParameter(para)
            };

            //範例化WCF服務
            ServiceReference.MyServiceClient client=new ServiceReference.MyServiceClient();
            //呼叫WCF服務提供的方法
            DataTable dt = client.ExeceteQuery(strSQL, paras);
            this.dataGridView1.DataSource = dt;

        }
    }
}

這樣就可以解決WCF不能直接序列化SqlParameter型別的問題了。

程式碼下載地址:點此下載

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com