InvalidOperationException: DataReader already active on this command - database

An error occurred while attempting to create a DB through the Uniy.
Below is a DLL file created by referring to "Mono.Data.Sqlite".
public class DbCon
{
private String Path;
private SqliteConnection connection;
private SqliteCommand Command;
public DbCon(String nPath)
{
Path = nPath;
}
private string getCoonectingString()
{
string strCon = String.Format(#"Data Source={0};Version=3;New=True;Compress=False;Read Only=False;MultipleActiveResultSets=True", Path);
return strCon;
}
public bool IsConnected()
{
if (connection != null && connection.State == System.Data.ConnectionState.Open)
return true;
return false;
}
public bool connect()
{
if (IsConnected() == true) return true;
connection = new SqliteConnection(getCoonectingString());
try
{
connection.Open();
if (connection.State == System.Data.ConnectionState.Open)
{
Command = new SqliteCommand();
Command.Connection = connection;
return true;
}
}
catch
{
return false;
}
return false;
}
private DataTable GetTable()
{
DataTable dataTable = new DataTable();
dataTable.Columns.Add("NAME", typeof(string));
dataTable.Columns.Add("EADATE", typeof(string));
dataTable.Columns.Add("LATIUDE", typeof(string));
dataTable.Columns.Add("HLTIUDE", typeof(string));
dataTable.Columns.Add("LRAD", typeof(Double));
dataTable.Columns.Add("NRAD", typeof(Double));
dataTable.Columns.Add("MRAD", typeof(Double));
dataTable.Columns.Add("NNL", typeof(string));
dataTable.Columns.Add("CREATDATE", typeof(string));
dataTable.Columns.Add("EDITDATE", typeof(string));
return dataTable;
}
/// <summary>
/// NAME
/// </summary>
/// <returns>DataTable</returns>
public DataTable GetNameListSel()
{
DataTable table = new DataTable();
table.Columns.Add("NAME", typeof(string));
String queryString = String.Format("SELECT DISTINCT NAME from IFPUG ");
Command.CommandText = queryString;
table.Load(Command.ExecuteReader());
Command.ExecuteReader().Close();
return table;
}
}
This script was taken by referring to Unity.
void Start()
{
string str = "C:/SEA.s3db";
DbCon nCon;
nCon = new DbCon(str);
bool result = nCon.connect();
Debug.Log(result);
if (result == true)
{
table = nCon.GetNameListSel();
Debug.Log("11");
}
else
{
Debug.Log("22");
}
}
I ran the function with the script above, but I checked to be connected, but I keep getting an error in the part where I run the function.
{InvalidOperationException: DataReader already active on this command}
I need your help. Please let me live.

Related

How to connect to SQL Server from .Net Core without using Entity Framework?

How can we connect to SQL Server from .Net Core without using Entity Framework?
you can simply use the traditional way which use SqlConnection
here is an example
public class BaseDataAccess
{
protected string ConnectionString { get; set; }
public BaseDataAccess()
{
}
{
public BaseDataAccess(string connectionString)
private SqlConnection GetConnection()
this.ConnectionString = connectionString;
}
{
if (connection.State != ConnectionState.Open)
SqlConnection connection = new SqlConnection(this.ConnectionString);
connection.Open();
return connection;
SqlCommand command = new SqlCommand(commandText, connection as SqlConnection);
}
protected DbCommand GetCommand(DbConnection connection, string commandText, CommandType commandType)
{
protected SqlParameter GetParameter(string parameter, object value)
command.CommandType = commandType;
return command;
}
{
parameterObject.Direction = ParameterDirection.Input;
SqlParameter parameterObject = new SqlParameter(parameter, value != null ? value : DBNull.Value);
return parameterObject;
}
SqlParameter parameterObject = new SqlParameter(parameter, type); ;
protected SqlParameter GetParameterOut(string parameter, SqlDbType type, object value = null, ParameterDirection parameterDirection = ParameterDirection.InputOutput)
{
if (type == SqlDbType.NVarChar || type == SqlDbType.VarChar || type == SqlDbType.NText || type == SqlDbType.Text)
{
}
parameterObject.Size = -1;
}
parameterObject.Direction = parameterDirection;
if (value != null)
{
parameterObject.Value = value;
}
else
{
parameterObject.Value = DBNull.Value;
}
return parameterObject;
DbCommand cmd = this.GetCommand(connection, procedureName, commandType);
protected int ExecuteNonQuery(string procedureName, List<DbParameter> parameters, CommandType commandType = CommandType.StoredProcedure)
{
int returnValue = -1;
try
{
using (SqlConnection connection = this.GetConnection())
{
if (parameters != null && parameters.Count > 0)
{
cmd.Parameters.AddRange(parameters.ToArray());
}
using (DbConnection connection = this.GetConnection())
returnValue = cmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
//LogException("Failed to ExecuteNonQuery for " + procedureName, ex, parameters);
throw;
}
return returnValue;
}
protected object ExecuteScalar(string procedureName, List<SqlParameter> parameters)
{
object returnValue = null;
try
{
{
}
DbCommand cmd = this.GetCommand(connection, procedureName, CommandType.StoredProcedure);
if (parameters != null && parameters.Count > 0)
{
cmd.Parameters.AddRange(parameters.ToArray());
}
returnValue = cmd.ExecuteScalar();
}
}
catch (Exception ex)
{
//LogException("Failed to ExecuteScalar for " + procedureName, ex, parameters);
throw;
return returnValue;
}
ds = cmd.ExecuteReader(CommandBehavior.CloseConnection);
protected DbDataReader GetDataReader(string procedureName, List<DbParameter> parameters, CommandType commandType = CommandType.StoredProcedure)
{
DbDataReader ds;
try
{
DbConnection connection = this.GetConnection();
{
DbCommand cmd = this.GetCommand(connection, procedureName, commandType);
if (parameters != null && parameters.Count > 0)
{
cmd.Parameters.AddRange(parameters.ToArray());
}
}
}
catch (Exception ex)
{
}
//LogException("Failed to GetDataReader for " + procedureName, ex, parameters);
throw;
}
return ds;
}
More can be find here
Update
you have to add nuget package
Install-Package System.Data.SqlClient
that is still confusing for me... .Net Core & .Net standard vs regular .Net: How do we know which packages we can use with .Net core?
Dependencies means that what you should have installed on your machine in order to use the package or nuget will install it for you
to understand more how dependencies work in .net take a look here
Note
that if the nuget package target .net standard library mostly work on both .net core and .net standard framework
If you surprised with BaseDataAccess class format in another answer and referenced article same as me, here is well formatted example... hopefully it will save you some time
public class BaseDataAccess
{
protected string ConnectionString { get; set; }
public BaseDataAccess()
{
}
public BaseDataAccess(string connectionString)
{
this.ConnectionString = connectionString;
}
private SqlConnection GetConnection()
{
SqlConnection connection = new SqlConnection(this.ConnectionString);
if (connection.State != ConnectionState.Open)
connection.Open();
return connection;
}
protected DbCommand GetCommand(DbConnection connection, string commandText, CommandType commandType)
{
SqlCommand command = new SqlCommand(commandText, connection as SqlConnection);
command.CommandType = commandType;
return command;
}
protected SqlParameter GetParameter(string parameter, object value)
{
SqlParameter parameterObject = new SqlParameter(parameter, value != null ? value : DBNull.Value);
parameterObject.Direction = ParameterDirection.Input;
return parameterObject;
}
protected SqlParameter GetParameterOut(string parameter, SqlDbType type, object value = null, ParameterDirection parameterDirection = ParameterDirection.InputOutput)
{
SqlParameter parameterObject = new SqlParameter(parameter, type); ;
if (type == SqlDbType.NVarChar || type == SqlDbType.VarChar || type == SqlDbType.NText || type == SqlDbType.Text)
{
parameterObject.Size = -1;
}
parameterObject.Direction = parameterDirection;
if (value != null)
{
parameterObject.Value = value;
}
else
{
parameterObject.Value = DBNull.Value;
}
return parameterObject;
}
protected int ExecuteNonQuery(string procedureName, List<DbParameter> parameters, CommandType commandType = CommandType.StoredProcedure)
{
int returnValue = -1;
try
{
using (SqlConnection connection = this.GetConnection())
{
DbCommand cmd = this.GetCommand(connection, procedureName, commandType);
if (parameters != null && parameters.Count > 0)
{
cmd.Parameters.AddRange(parameters.ToArray());
}
returnValue = cmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
//LogException("Failed to ExecuteNonQuery for " + procedureName, ex, parameters);
throw;
}
return returnValue;
}
protected object ExecuteScalar(string procedureName, List<SqlParameter> parameters)
{
object returnValue = null;
try
{
using (DbConnection connection = this.GetConnection())
{
DbCommand cmd = this.GetCommand(connection, procedureName, CommandType.StoredProcedure);
if (parameters != null && parameters.Count > 0)
{
cmd.Parameters.AddRange(parameters.ToArray());
}
returnValue = cmd.ExecuteScalar();
}
}
catch (Exception ex)
{
//LogException("Failed to ExecuteScalar for " + procedureName, ex, parameters);
throw;
}
return returnValue;
}
protected DbDataReader GetDataReader(string procedureName, List<DbParameter> parameters, CommandType commandType = CommandType.StoredProcedure)
{
DbDataReader ds;
try
{
DbConnection connection = this.GetConnection();
{
DbCommand cmd = this.GetCommand(connection, procedureName, commandType);
if (parameters != null && parameters.Count > 0)
{
cmd.Parameters.AddRange(parameters.ToArray());
}
ds = cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
}
catch (Exception ex)
{
//LogException("Failed to GetDataReader for " + procedureName, ex, parameters);
throw;
}
return ds;
}
}
Here is a solution for an ASP.NET MVC Core 3.1 project tested in Visual Studio 2019 community edition.
Create a small database in SQL Express.
Then add a few lines to appsettings.json for the connection strings:
"ConnectionStrings": {
//PROD on some server
"ProdConnection": "Server=somePRODServerofYours;Database=DB_xxxxx_itemsubdb;User Id=DB_xxxxx_user;Password=xxsomepwdxx;Integrated Security=false;MultipleActiveResultSets=true;encrypt=true",
//DEV on localhost
"DevConnection": "Server=someDEVServerofYours;Database=DB_xxxxx_itemsubdb;User Id=DB_xxxxx_user;Password=xxsomepwdxx;Integrated Security=false;MultipleActiveResultSets=true;"
},
Then use code similar to the following in your controller ....
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Configuration;
using System.Data.SqlClient;
using System.Data;
namespace SomeNameSpace.Controllers
{
//This Model class should be saved somewhere else in your project.
//It is placed here for simplicity.
public class XtraSimpleContent
{
public string UserName { get; set; }
public string References { get; set; }
public string CreatedTime { get; set; }
}
public class CodeNotesController : Controller
{
public IConfiguration Configuration { get; }
public string connStr = String.Empty;
public CodeNotesController(IConfiguration configuration, IWebHostEnvironment env)
{
Configuration = configuration;
if (env.IsDevelopment())
{
connStr = Configuration.GetConnectionString("DevConnection");
}
else
{
connStr = Configuration.GetConnectionString("ProdConnection");
}
}
[HttpGet]
public async Task<IActionResult> CodeActionMethodToConnectToSQLnetCore()
{
//add using System.Data.SqlClient;
// using System.Data;
//Along with the using statements, you need the system assembly reference.
//To add assembly you can do the following.
// install nuget package. Right Click on Project > Manage Nuget Packages >
// Search & install 'System.Data.SqlClient' and make sure it is compatible with the type of project (Core/Standard);
List<XtraSimpleContent> aListOfItems = new List<XtraSimpleContent>();
string commandText = #"SELECT * FROM [dbo].[ItemSubmissions]
WHERE SUBMITTEREMAIL = #SUBMITTEREMAIL
ORDER BY CreationDatetime DESC";
using (var connection = new SqlConnection(connStr))
{
await connection.OpenAsync(); //vs connection.Open();
using (var tran = connection.BeginTransaction())
{
using (var command = new SqlCommand(commandText, connection, tran))
{
try
{
command.Parameters.Add("#SUBMITTEREMAIL", SqlDbType.NVarChar);
command.Parameters["#SUBMITTEREMAIL"].Value = "me#someDomain.org";
SqlDataReader rdr = await command.ExecuteReaderAsync(); // vs also alternatives, command.ExecuteReader(); or await command.ExecuteNonQueryAsync();
while (rdr.Read())
{
var itemContent = new XtraSimpleContent();
itemContent.UserName = rdr["RCD_SUBMITTERNAME"].ToString();
itemContent.References = rdr["RCD_REFERENCES"].ToString();
itemContent.CreatedTime = rdr["CreationDatetime"].ToString();
aListOfItems.Add(itemContent);
}
await rdr.CloseAsync();
}
catch (Exception Ex)
{
await connection.CloseAsync()
string msg = Ex.Message.ToString();
tran.Rollback();
throw;
}
}
}
}
string totalinfo = string.Empty;
foreach (var itm in aListOfItems)
{
totalinfo = totalinfo + itm.UserName + itm.References + itm.CreatedTime;
}
return Content(totalinfo);
}
}
}
Test it with something like:
https://localhost:44302/CodeNotes/CodeActionMethodToConnectToSQLnetCore
With UkrGuru.SqlJson package
appsettings.json:
"ConnectionStrings": {
"SqlJsonConnection": "Server=localhost;Database=SqlJsonDemo;Integrated Security=SSPI"
}
Startup.cs
services.AddSqlJson(Configuration.GetConnectionString("SqlJsonConnection"));
DbController.cs
[ApiController]
[Route("api/[controller]")]
public class DbController : ControllerBase
{
private readonly string _prefix = "api.";
private readonly DbService _db;
public DbController(DbService db) => _db = db;
[HttpGet("{proc}")]
public async Task<string> Get(string proc, string data = null)
{
try
{
return await _db.FromProcAsync($"{_prefix}{proc}", data);
}
catch (Exception ex)
{
return await Task.FromResult($"Error: {ex.Message}");
}
}
[HttpPost("{proc}")]
public async Task<dynamic> Post(string proc, [FromBody] dynamic data = null)
{
try
{
return await _db.FromProcAsync<dynamic>($"{_prefix}{proc}",
(object)data == null ? null : data);
}
catch (Exception ex)
{
return await Task.FromResult($"Error: {ex.Message}");
}
}
}

Reader always returns NULL

I'm new to C#. I want to write an application that can easily connect to a SQL Server database. I have a separate DBConnection class, and I want to call this class from any form.
The problem is that my "reader" always returns Null.
class DBconnection
{
private SqlConnection conn;
private SqlCommand cmd;
private SqlDataReader rdr;
private DataTable dt;
private SqlConnection MyConnection
{
get
{
if (this.conn == null)
{
this.conn = new SqlConnection(DrivingSchool.Properties.Settings.Default.cdsConnectionString);
}
return conn;
}
}
private SqlCommand MyCommand
{
get
{
if (cmd == null)
{
cmd = new SqlCommand();
MyCommand.Connection = conn;
}
return cmd;
}
}
public DataTable RunQuery(string query)
{
dt = new DataTable();
MyCommand.CommandText = query;
MyCommand.Connection = conn;
MyConnection.Open();
rdr = MyCommand.ExecuteReader(CommandBehavior.CloseConnection);
if(rdr.HasRows)
{
dt.Load(rdr);
}
MyConnection.Close();
return dt;
}
}
It seems to me that in factoring out the creation of the connection and SqlCommand that you have over-complicated your code.
To fill a DataTable, you should use an SqlDataAdapter (or the appropriate DataAdapter for whatever database you use), something like this:
static public DataTable GetDataTableFromQuery(string queryString)
{
DataTable dt = null;
string connStr = DrivingSchool.Properties.Settings.Default.cdsConnectionString;
using (SqlDataAdapter da = new SqlDataAdapter(queryString, connStr))
{
da.Fill(dt);
}
return dt;
}

fill textbox on second combobox selection changed in cascading combobox in windows form using c#

I have 2 cascading combo-box in windows form application. I have textbox for price and unit. when I select first combobox, second combobox gets populated. I want textbox for price and unit to be filled only on second combobox selection.
My problem is when the form is loaded both textboxes are filled with values from table and not on combobox selection changed.
my code is:
private void Purchase_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'supplierDataSet.Supplier' table. You can move, or remove it, as needed.
this.supplierTableAdapter.Fill(this.supplierDataSet.Supplier);
fillName();
comboBoxName.SelectedIndex = -1;
}
private void fillName()
{
string str = "Select distinct Item_Name from Item";
using (SqlConnection con = new SqlConnection(#"Data Source=ashish-pc\;Initial Catalog=HMS;Integrated Security=True"))
{
using (SqlCommand cmd = new SqlCommand(str, con))
{
using (SqlDataAdapter adp = new SqlDataAdapter(cmd))
{
DataTable dtItem = new DataTable();
adp.Fill(dtItem);
comboBoxName.DataSource = dtItem;
comboBoxName.DisplayMember = "Item_Name";
comboBoxName.ValueMember = "Item_Name";
}
}
}
}
private void fillMake()
{
string str = "Select Item_Make from Item Where Item_Name=#Item_Name";
using (SqlConnection con = new SqlConnection(#"Data Source=ashish-pc\;Initial Catalog=HMS;Integrated Security=True"))
{
using (SqlCommand cmd = new SqlCommand(str, con))
{
cmd.Parameters.AddWithValue("#Item_Name", comboBoxName.Text);
using (SqlDataAdapter adp = new SqlDataAdapter(cmd))
{
DataTable dtItem = new DataTable();
adp.Fill(dtItem);
comboBoxMake.DataSource = dtItem;
comboBoxMake.ValueMember = "Item_Make";
comboBoxMake.DisplayMember = "Item_Make";
}
}
}
}
private void comboBoxName_SelectedIndexChanged_1(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(comboBoxName.Text))
{
comboBoxMake.Enabled = true;
fillMake();
comboBoxMake.SelectedIndex = -1;
}
}
private void comboBoxMake_SelectedIndexChanged_1(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(comboBoxMake.Text))
{
textBoxPrice.Enabled = true;
textBoxUoM.Enabled = true;
}
SqlConnection con = new SqlConnection(#"Data Source=ashish-pc\;Initial Catalog=HMS;Integrated Security=True");
SqlCommand cmd = new SqlCommand("Select * from Item Where Item_Make='" + comboBoxMake.Text + "' AND Item_Name='" + comboBoxName.Text + "'", con);
SqlDataReader reader;
try
{
if (con.State == ConnectionState.Closed)
{
con.Open();
}
reader = cmd.ExecuteReader();
while (reader.Read())
{
textBoxPrice.Text = Convert.ToString(reader["Price"]);
textBoxUoM.Text = Convert.ToString(reader["Unit"]);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
if (con.State == ConnectionState.Open)
{
con.Close();
}
}
}
I am stuck here. please help.
Try changing SelectedIndex = -1 to SelectedItem = -1 in Purchase_Load and ComboBox1_SelectedIndexChanged.

Serializing a DataSet/DataTable with properties in json.net

I'm looking a solution to serialize dataset to json, but I need to get the rowstate in json.
Does json.net serialize / deserialize properties of the dataset / datatable, like rowstate? I can only find examples with row value.
Thanks.
No, the DataTableConverter that ships with Json.Net does not serialize the RowState. If you really need this value in the JSON, it should be possible to create a custom JsonConverter to output it. However, it will not be possible to deserialize the RowState back to its original value due to the fact that it is a read-only property. (In fact, this value is calculated from a variety of internal state variables.)
I wrote a custom converter for DataSet which keeps the row state. The DataSet class can write the schema as xml with WriteXmlSchema, and it can write the data including the rowstate with WriteXml(sw, XmlWriteMode.DiffGram). This produces two strings that are properties in the DataSetSerializer class, which then can be serialized and deserialized with JsonSerializer. Here is the code in a test class:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Data;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace TestProject3
{
public class DataSetConverter : JsonConverter<DataSet>
{
private class DataSetSerializer
{
public string SchemaString { get; set; }
public string DataString { get; set; }
private static string GetSchema(DataSet ds)
{
using (var sw = new StringWriter())
{
ds.WriteXmlSchema(sw);
return sw.ToString();
}
}
private static string GetData(DataSet ds)
{
using (var sw = new StringWriter())
{
ds.WriteXml(sw, XmlWriteMode.DiffGram);
return sw.ToString();
}
}
private DataSet GetDataSet()
{
var ds = new DataSet();
using (var sr1 = new StringReader(SchemaString))
{
ds.ReadXmlSchema(sr1);
}
using (var sr2 = new StringReader(DataString))
{
ds.ReadXml(sr2, XmlReadMode.DiffGram);
}
return ds;
}
public static string Serialize(DataSet ds)
{
var serializer = new DataSetSerializer() { SchemaString = GetSchema(ds), DataString = GetData(ds) };
return JsonSerializer.Serialize<DataSetSerializer>(serializer);
}
public static DataSet DeSerialize(string s)
{
var serializer = JsonSerializer.Deserialize<DataSetSerializer>(s);
return serializer.GetDataSet();
}
}
public override DataSet Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DataSetSerializer.DeSerialize(reader.GetString());
}
public override void Write(Utf8JsonWriter writer, DataSet value, JsonSerializerOptions options)
{
writer.WriteStringValue(DataSetSerializer.Serialize(value));
}
}
[TestClass]
public class TestDataSet
{
private DataSet CreateTestDataSet()
{
var ds = new DataSet();
var dt = ds.Tables.Add();
dt.Columns.Add("A");
dt.Columns.Add("B");
dt.Rows.Add("A1", "B1");
var dr = dt.Rows.Add("A2", "B2");
ds.AcceptChanges();
dr["A"] = "AA2";
return ds;
}
private void CheckTestDataSet(DataSet ds)
{
var dt = ds.Tables[0];
Assert.IsTrue(dt.Rows[0].RowState == DataRowState.Unchanged && dt.Rows[1].RowState == DataRowState.Modified);
}
[TestMethod]
public void TestDataSetConverter()
{
var ds = CreateTestDataSet();
var serializeOptions = new JsonSerializerOptions { Converters = { new DataSetConverter() } };
var jsonstring = JsonSerializer.Serialize(ds, serializeOptions);
ds = JsonSerializer.Deserialize<DataSet>(jsonstring, serializeOptions);
CheckTestDataSet(ds);
}
}
}
I needed a solution that maintained RowState for DataSets and DataTables for a legacy app migrating from SOAP calls to WebApi calls but using Newtonsoft rather than System.Text.Json. Thank you Alex for the last answer which was just what I needed.
Here is a Newtonsoft version of the same thing:
using System;
using System.Data;
using System.IO;
using Newtonsoft.Json;
using Xunit;
namespace DataSetsAndTablesTester
{
public class CustomJsonConverter_DataSet : JsonConverter<DataSet>
{
private class DataSetSerializer
{
public string SchemaString { get; set; }
public string DataString { get; set; }
private static string GetSchema(DataSet ds)
{
using (var sw = new StringWriter())
{
ds.WriteXmlSchema(sw);
return sw.ToString();
}
}
private static string GetData(DataSet ds)
{
using (var sw = new StringWriter())
{
ds.WriteXml(sw, XmlWriteMode.DiffGram);
return sw.ToString();
}
}
private DataSet GetDataSet()
{
var ds = new DataSet();
using (var sr1 = new StringReader(SchemaString))
{
ds.ReadXmlSchema(sr1);
}
using (var sr2 = new StringReader(DataString))
{
ds.ReadXml(sr2, XmlReadMode.DiffGram);
}
return ds;
}
public static string Serialize(DataSet ds)
{
var serializer = new DataSetSerializer() { SchemaString = GetSchema(ds), DataString = GetData(ds) };
return JsonConvert.SerializeObject(serializer);
}
public static DataSet DeSerialize(string s)
{
var serializer = JsonConvert.DeserializeObject<DataSetSerializer>(s);
return serializer.GetDataSet();
}
}
public override void WriteJson(JsonWriter writer, DataSet value, JsonSerializer serializer)
{
if (value == null)
throw new Exception("Passed in DataSet is null");
writer.WriteValue(DataSetSerializer.Serialize(ds: value));
}
public override DataSet ReadJson(JsonReader reader, Type objectType, DataSet existingValue, bool hasExistingValue, JsonSerializer serializer)
{
return DataSetSerializer.DeSerialize((string)reader.Value);
}
}
public class CustomJsonConverter_DataTable : JsonConverter<DataTable>
{
private class DataTableSerializer
{
public string SchemaString { get; set; }
public string DataString { get; set; }
private static string GetSchema(DataTable dt)
{
using (var sw = new StringWriter())
{
dt.WriteXmlSchema(sw);
return sw.ToString();
}
}
private static string GetData(DataTable dt)
{
using (var sw = new StringWriter())
{
dt.WriteXml(sw, XmlWriteMode.DiffGram);
return sw.ToString();
}
}
private DataTable GetDataTable()
{
var dt = new DataTable();
using (var sr1 = new StringReader(SchemaString))
{
dt.ReadXmlSchema(sr1);
}
using (var sr2 = new StringReader(DataString))
{
dt.ReadXml(sr2);
}
return dt;
}
public static string Serialize(DataTable dt)
{
var serializer = new DataTableSerializer() { SchemaString = GetSchema(dt), DataString = GetData(dt) };
return JsonConvert.SerializeObject(serializer);
}
public static DataTable DeSerialize(string s)
{
var serializer = JsonConvert.DeserializeObject<DataTableSerializer>(s);
return serializer.GetDataTable();
}
}
public override void WriteJson(JsonWriter writer, DataTable value, JsonSerializer serializer)
{
if (value == null)
throw new Exception("Passed in DataTable is null");
if (string.IsNullOrEmpty(value.TableName))
throw new Exception("Passed in DataTable Name is null or empty");
writer.WriteValue(DataTableSerializer.Serialize(dt: value));
}
public override DataTable ReadJson(JsonReader reader, Type objectType, DataTable existingValue, bool hasExistingValue, JsonSerializer serializer)
{
return DataTableSerializer.DeSerialize((string)reader.Value);
}
}
public class JsonConverterTester
{
public void TestJsonDataSetConverter()
{
DataSet ds = CreateTestDataSet();
String json = JsonConvert.SerializeObject(value: ds, converters: new CustomJsonConverter_DataSet());
Console.WriteLine(json);
DataSet ds2 = JsonConvert.DeserializeObject<DataSet>(value: json, converters: new CustomJsonConverter_DataSet());
CheckTestDataSet(ds2);
}
public void TestJsonDataTableConverter()
{
DataTable dt = CreateTestDataTable();
String json = JsonConvert.SerializeObject(value: dt, converters: new CustomJsonConverter_DataTable());
Console.WriteLine(json);
DataTable dt2 = JsonConvert.DeserializeObject<DataTable>(value: json, converters: new CustomJsonConverter_DataTable());
CheckTestDataTable(dt2);
}
private DataSet CreateTestDataSet()
{
var ds = new DataSet();
var dt = ds.Tables.Add();
dt.Columns.Add("A");
dt.Columns.Add("B");
dt.Rows.Add("A1", "B1");
var dr = dt.Rows.Add("A2", "B2");
ds.AcceptChanges();
dr["A"] = "AA2";
return ds;
}
private void CheckTestDataSet(DataSet ds)
{
var dt = ds.Tables[0];
Assert.True(dt.Rows[0].RowState == DataRowState.Unchanged && dt.Rows[1].RowState == DataRowState.Modified);
}
private DataTable CreateTestDataTable()
{
var dt = new DataTable();
dt.TableName = "TestTable";
dt.Columns.Add("A");
dt.Columns.Add("B");
dt.Rows.Add("A1", "B1");
var dr = dt.Rows.Add("A2", "B2");
dt.AcceptChanges();
dr["A"] = "AA2";
return dt;
}
private void CheckTestDataTable(DataTable dt)
{
Assert.True(dt.Rows[0].RowState == DataRowState.Unchanged && dt.Rows[1].RowState == DataRowState.Modified);
}
}
}

Async call of WCF using Duplex Communication to get Database change

I am implementing and WCF Async service using WsDualHttpBinding binding for duplex communication to get database changes.
I have implemented the Service but I dont know how to call it from Client application.
Here is the code.
The below code is WCF Service
[ServiceContract()]
public interface ICustomerService
{
[OperationContract(IsOneWay = true)]
void GetAllCustomer();
}
public interface ICustomerServiceCallback
{
[OperationContract(IsOneWay = true)]
void Callback(Customer[] customers);
}
[ServiceContract(Name = "ICustomerService",
CallbackContract = typeof(CustomerServiceLibrary.ICustomerServiceCallback),
SessionMode = SessionMode.Required)]
public interface ICustomerServiceAsync
{
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginGetAllCustomer(AsyncCallback callback, object asyncState);
void EndGetAllCustomer(IAsyncResult result);
}
[DataContract]
public class Customer
{
[DataMember]
public string Name
{
get;
set;
}
}
}
public class CustomerService :ICustomerService,IDisposable
{
List<Customer> Customers = null;
ICustomerServiceCallback callback;
Customer customer = null;
string constr = "Data Source=.;Initial Catalog=WPFCache;Persist Security Info=True;User ID=sa;Password=Password$2";
public CustomerService()
{
callback = OperationContext.Current.GetCallbackChannel<ICustomerServiceCallback>();
SqlDependency.Start(constr);
}
public void GetAllCustomer()
{
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand())
{
con.Open();
cmd.Connection = con;
cmd.CommandText = "GetHero";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Notification = null;
// Create the associated SqlDependency
SqlDependency dep = new SqlDependency(cmd);
dep.OnChange += new OnChangeEventHandler(dep_OnChange);
SqlDataReader dr = cmd.ExecuteReader();
Customers = new List<Customer>();
while (dr.Read())
{
customer = new Customer();
customer.Name = dr.GetString(0);
Customers.Add(customer);
}
}
callback.Callback(Customers.ToArray());
}
}
void dep_OnChange(object sender, SqlNotificationEventArgs e)
{
try
{
if (e.Type == SqlNotificationType.Change)
{
GetAllCustomer();
}
}
catch (Exception ex)
{
throw ex;
}
}
public void Dispose()
{
SqlDependency.Stop(constr);
}
}
I have hosted this WCF Async Service as self hosting in a Console Application.
Here the hosting code
class Program
{
static void Main(string[] args)
{
StartService();
}
internal static ServiceHost myServiceHost = null;
internal static void StartService()
{
Uri httpbaseAddress = new Uri("http://localhost:8087/CustomerService/");
Uri[] baseAdresses = { httpbaseAddress };
myServiceHost = new ServiceHost(typeof(CustomerServiceLibrary.CustomerService));
myServiceHost.AddServiceEndpoint(typeof(CustomerServiceLibrary.ICustomerService), new WSDualHttpBinding(), httpbaseAddress);
ServiceDescription serviceDesciption = myServiceHost.Description;
foreach (ServiceEndpoint endpoint in serviceDesciption.Endpoints)
{
Console.WriteLine("Endpoint - address: {0}", endpoint.Address);
Console.WriteLine(" - binding name:\t\t{0}", endpoint.Binding.Name);
Console.WriteLine(" - contract name:\t\t{0}", endpoint.Contract.Name);
Console.WriteLine();
}
myServiceHost.Open();
Console.WriteLine("Press enter to stop.");
Console.ReadKey();
if (myServiceHost.State != CommunicationState.Closed)
myServiceHost.Close();
}
}
In client Application have crated a DuplexChannel factory instance
Here is the Code.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
EndpointAddress address = new EndpointAddress(new Uri("http://localhost:8087/CustomerService"));
WSDualHttpBinding wsDualBinding = new WSDualHttpBinding();
DuplexChannelFactory<ICustomerServiceAsync> client = new DuplexChannelFactory<ICustomerServiceAsync>(new InstanceContext(this), wsDualBinding, address);
App.channel = client.CreateChannel();
}
Now My question is How I can call the
BeginGetAllCustomer
EndGetAllCustomer
Method of My service.
Help me.... A big thanks in Advance ...
You need:
InstanceContext instanceContext = new InstanceContext(YOUR_OBJECT_IMPLMENTS_CALLBACK);
and
using (App.channel as IDisposable)
{
App.channel.YOUR_METHOD_HERE();
}
from this example:
endPointAddr = "net.tcp://" + textBox2.Text + ":8000/FIXMarketDataHub";
NetTcpBinding tcpBinding = new NetTcpBinding();
tcpBinding.TransactionFlow = false;
tcpBinding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
tcpBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
tcpBinding.Security.Mode = SecurityMode.None;
EndpointAddress endpointAddress = new EndpointAddress(endPointAddr);
Append("Attempt to connect to: " + endPointAddr);
InstanceContext instanceContext = new InstanceContext(??);
IMarketDataPub proxy = DuplexChannelFactory<IMarketDataPub>.CreateChannel(instanceContext,tcpBinding, endpointAddress);
using (proxy as IDisposable)
{
proxy.Subscribe();
Append("Subscribing to market data");
}
See also microsoft example

Resources