I am trying pass an argument to a NUnit test after reading a CSV file i.e.
[Test, TestCaseSource(typeof(RegistrationData), "GetTestData")]
public void RegisterUserTest(RegistrationData registrationData)
{
RegisterNewUser registration = new RegisterNewUser(this.driver);
this.driver.Navigate().GoToUrl(baseURL + "/mercuryregister.php");
registration.registerNewUser(registrationData);
}
but I get the error:
System.InvalidCastException : Unable to cast object of type
'RegisterUser.RegistrationData' to type
'System.Collections.IEnumerable'.RegisterUser.UserRegistrationTest.RegisterUserTest
private RegistrationData GetTestData()
{
DataTable dt = DataTable.New.ReadCsv(#"C:\datafolder\regdata.csv");
RegistrationData registrationData = new RegistrationData();
foreach (Row row in dt.Rows)
{
registrationData.setfirstName(row["FirstName"]);
registrationData.setfirstName(row["LastName"]);
registrationData.setPhone(row["Phone"]);
registrationData.setUserName(row["UserName"]);
registrationData.setAddress1(row["Add1"]);
registrationData.setAddress2(row["Add2"]);
registrationData.setCity(row["City"]);
registrationData.setState(row["State"]);
registrationData.setPostalcode(row["Postalcode"]);
registrationData.setCountry(row["Country"]);
registrationData.setEmail(row["Email"]);
registrationData.setPassword(row["Password"]);
registrationData.setConfimPassword(row["Cpassword"]);
}
// return new RegistrationData[][] { { registrationData } };
return registrationData;
}
Example of the ModelTestCaseSource:
public class ModelTestCaseSource
{
public IEnumerable<TestCaseData> GetTestCases()
{
DataTable dt = DataTable.New.ReadCsv(#"C:\datafolder\regdata.csv");
foreach (Row row in dt.Rows)
{
var registrationData = new RegistrationData();
registrationData.setfirstName(row["FirstName"]);
registrationData.setfirstName(row["LastName"]);
registrationData.setPhone(row["Phone"]);
registrationData.setUserName(row["UserName"]);
registrationData.setAddress1(row["Add1"]);
registrationData.setAddress2(row["Add2"]);
registrationData.setCity(row["City"]);
registrationData.setState(row["State"]);
registrationData.setPostalcode(row["Postalcode"]);
registrationData.setCountry(row["Country"]);
registrationData.setEmail(row["Email"]);
registrationData.setPassword(row["Password"]);
registrationData.setConfimPassword(row["Cpassword"]);
yield return new TestCaseData(new object[] { registrationData });
}
}
}
Usage:
[Test, TestCaseSource(typeof(ModelTestCaseSource), "GetTestCases")]
public void RegisterUserTest(RegistrationData registrationData)
{
RegisterNewUser registration = new RegisterNewUser(this.driver);
this.driver.Navigate().GoToUrl(baseURL + "/mercuryregister.php");
registration.registerNewUser(registrationData);
}
Related
I have this situation:
private static EntityBuilderCore entityBuilderCore = ServiceFactory.Create<EntityBuilderCore>();
private List<Set> SplitBySetId(List<Step> stepList)
{
List<Set> outputSetList = new List<Set>();
using (entityBuilderCore)
{
stepList.ForEach(step =>
{
// For each step, I find the corrispectives set's ids (one or more).
// Then, I create the Set
List<int> setIdList = entityBuilderCore.GetSetIdByStep(step);
// Create Sets and adding to the output list
setIdList.ToList().ForEach(id =>
{
if (!outputSetList.Any(set => set.Id == id))
outputSetList.Add((Set)entityBuilderCore.GetEntity(typeof(Set), id));
});
});
}
return outputSetList;
}
But I can have A LOT of steps subdivided in many Set... so I was thinking to parallelizate in this way (looks the add part):
private List<Set> SplitBySetId(List<Step> stepList)
{
List<Set> outputSetList = new List<Set>();
using (entityBuilderCore)
{
stepList.ForEach(step =>
{
// For each step, I find the corrispectives set's ids (one or more).
// Then, I create the Set
List<int> setIdList = entityBuilderCore.GetSetIdByStep(step);
// Create Sets and adding to the output list
var tempList = setIdList.Distinct()
.AsParallel()
.Where(id => !outputSetList.Any(set => set.Id == id))
.Select(setId => (Set)entityBuilderCore.GetEntity(typeof(Set), setId));
outputSetList.AddRange(tempList);
});
}
return outputSetList;
}
But I'm not sure about the thread-safety of the entityBuilderCore. The core is this:
class EntityBuilderCore : CoreBase
{
private static EntityRepository Repository;
protected override string _connectionString
{
get { return ConfigurationService.Instance.GetValue("connessione_database_sinistriweb"); }
}
private EntityBuilderCore()
{
Repository = new EntityRepository() { ConnectionString = _connectionString };
}
public BaseEntity GetEntity(Type entityType, int id)
{
return EntityBuilder.BuildEntity(entityType, Repository.GetEntity(entityType, id));
}
// ...
public List<int> GetSetIdByStep(Step step)
{
return Repository.GetSetIdByStep(step);
}
}
class EntityRepository : RepositoryBase
{
Dictionary<Type, string> tableDictionary = new Dictionary<Type, string>();
public EntityRepository()
{
tableDictionary.Add(typeof(SQL), "PROCESSI.DBO.GFE_SQL");
tableDictionary.Add(typeof(Step), "PROCESSI.DBO.GFE_STEP");
tableDictionary.Add(typeof(StepSet), "PROCESSI.DBO.GFE_SET");
}
public DataRow GetEntity(Type systemType, int id)
{
string entityTable;
tableDictionary.TryGetValue(systemType, out entityTable);
using (SqlConnection connection = new SqlConnection(ConnectionString))
using (SqlCommand command = new SqlCommand(string.Format("SELECT * FROM {0} WHERE ID = #ID", entityTable), connection))
{
connection.Open();
command.Parameters.Add("#ID", System.Data.SqlDbType.Int).Value = id;
using (SqlDataReader dr = command.ExecuteReader())
{
if (dr.Read())
{
DataTable entityDataTable = new DataTable();
SqlDataAdapter dataAdapter = new SqlDataAdapter();
dataAdapter.SelectCommand = command;
connection.Close();
dataAdapter.Fill(entityDataTable);
return entityDataTable.Rows[0];
}
}
}
return null;
}
public List<int> GetSetIdByStep(Step step)
{
// bla bla
}
// ...
}
I will prefer to use only ONE entityBuilderCore also in the EntityBuilder class. I prefer to not instantiate every time the entityBuilderCore, I think is useless. But I'm afraid is not thread safety, because the SplitBySetId method is used by many Tasks at the same time
class EntityBuilder
{
public static BaseEntity BuildEntity(Type entityType, DataRow dr)
{
if (entityType == typeof(SQL))
return BuildSQL(dr);
if (entityType == typeof(Step))
return BuildStep(dr);
if (entityType == typeof(Set))
return BuildSet(dr);
return null;
}
//...
private static Step BuildStep(DataRow dr)
{
using (EntityBuilderCore entityBuilderCore = ServiceFactory.Create<EntityBuilderCore>())
{
Step s = new Step()
{
Id = Convert.ToInt16(dr["ID"]),
//... bla bla
};
return s;
}
}
private static Set BuildSet(DataRow dr)
{
using (EntityBuilderCore entityBuilderCore = ServiceFactory.Create<EntityBuilderCore>())
{
Set s = new Set()
{
Id = Convert.ToInt16(dr["ID"]),
//...
};
return s;
}
}
}
Is there more efficient way to build HTML table than the one I'm trying on right now?
I'm getting an object and it has some list of entities in it. So I need to pass through each of them and build first a cell and then add it to an row and finally adding it in table.
The thing I'm trying on is totally messy, kind of works, but it has too much of redundant code.
public static string CreateNotificationMailMessage(NotificationMailMessage mailMessageObject)
{
var table = new HtmlTable();
var mailMessage = new StringBuilder();
string html;
if (mailMessageObject.InvalidCompanies.Any())
{
HtmlTableRow row;
HtmlTableCell cell;
foreach (var invalidCompany in mailMessageObject.InvalidCompanies)
{
row = new HtmlTableRow();
cell = new HtmlTableCell();
cell.InnerText = invalidCompany.BusinessName;
row.Cells.Add(cell);
cell.InnerText = invalidCompany.SwiftBIC;
row.Cells.Add(cell);
cell.InnerText = invalidCompany.IBAN;
row.Cells.Add(cell);
table.Rows.Add(row);
}
}
using (var sw = new StringWriter())
{
table.RenderControl(new HtmlTextWriter(sw));
html = sw.ToString();
}
mailMessage.AppendFormat(html);
return mailMessage.ToString();
}
At the end I want to return text version of created HTML table.
The problem is that I have much more properties than those 3 (BusinessName, SwiftBIC and IBAN) and plus I have one more list of objects inside of mailMessageObject, so the code would be terrible.
Anybody has an idea how to solve this in simpler and cleaner way?
I would just like to supplement Steve Harris' answer with a class library that is a little more built out. His answer is a totally elegant solution that made a windows service I was creating not have to reference System.Web for no good reason!
Classes Defined:
public static class Html
{
public class Table : HtmlBase, IDisposable
{
public Table(StringBuilder sb, string classAttributes = "", string id = "") : base(sb)
{
Append("<table");
AddOptionalAttributes(classAttributes, id);
}
public void StartHead(string classAttributes = "", string id = "")
{
Append("<thead");
AddOptionalAttributes(classAttributes, id);
}
public void EndHead()
{
Append("</thead>");
}
public void StartFoot(string classAttributes = "", string id = "")
{
Append("<tfoot");
AddOptionalAttributes(classAttributes, id);
}
public void EndFoot()
{
Append("</tfoot>");
}
public void StartBody(string classAttributes = "", string id = "")
{
Append("<tbody");
AddOptionalAttributes(classAttributes, id);
}
public void EndBody()
{
Append("</tbody>");
}
public void Dispose()
{
Append("</table>");
}
public Row AddRow(string classAttributes = "", string id = "")
{
return new Row(GetBuilder(), classAttributes, id);
}
}
public class Row : HtmlBase, IDisposable
{
public Row(StringBuilder sb, string classAttributes = "", string id = "") : base(sb)
{
Append("<tr");
AddOptionalAttributes(classAttributes, id);
}
public void Dispose()
{
Append("</tr>");
}
public void AddCell(string innerText, string classAttributes = "", string id = "", string colSpan = "")
{
Append("<td");
AddOptionalAttributes(classAttributes, id, colSpan);
Append(innerText);
Append("</td>");
}
}
public abstract class HtmlBase
{
private StringBuilder _sb;
protected HtmlBase(StringBuilder sb)
{
_sb = sb;
}
public StringBuilder GetBuilder()
{
return _sb;
}
protected void Append(string toAppend)
{
_sb.Append(toAppend);
}
protected void AddOptionalAttributes(string className = "", string id = "", string colSpan = "")
{
if (!id.IsNullOrEmpty())
{
_sb.Append($" id=\"{id}\"");
}
if (!className.IsNullOrEmpty())
{
_sb.Append($" class=\"{className}\"");
}
if (!colSpan.IsNullOrEmpty())
{
_sb.Append($" colspan=\"{colSpan}\"");
}
_sb.Append(">");
}
}
}
Usage:
StringBuilder sb = new StringBuilder();
using (Html.Table table = new Html.Table(sb, id: "some-id"))
{
table.StartHead();
using (var thead = table.AddRow())
{
thead.AddCell("Category Description");
thead.AddCell("Item Description");
thead.AddCell("Due Date");
thead.AddCell("Amount Budgeted");
thead.AddCell("Amount Remaining");
}
table.EndHead();
table.StartBody();
foreach (var alert in alertsForUser)
{
using (var tr = table.AddRow(classAttributes: "someattributes"))
{
tr.AddCell(alert.ExtendedInfo.CategoryDescription);
tr.AddCell(alert.ExtendedInfo.ItemDescription);
tr.AddCell(alert.ExtendedInfo.DueDate.ToShortDateString());
tr.AddCell(alert.ExtendedInfo.AmountBudgeted.ToString("C"));
tr.AddCell(alert.ExtendedInfo.ItemRemaining.ToString("C"));
}
}
table.EndBody();
}
return sb.ToString();
As I've recently come to play with creating IDisposable classes, I think this would be both efficient for this specific task, and much easier to read:
Create some very simple classes
/// <summary>
/// https://stackoverflow.com/a/36476600/2343
/// </summary>
public class Table : IDisposable
{
private StringBuilder _sb;
public Table(StringBuilder sb, string id = "default", string classValue="")
{
_sb = sb;
_sb.Append($"<table id=\"{id}\" class=\"{classValue}\">\n");
}
public void Dispose()
{
_sb.Append("</table>");
}
public Row AddRow()
{
return new Row(_sb);
}
public Row AddHeaderRow()
{
return new Row(_sb, true);
}
public void StartTableBody()
{
_sb.Append("<tbody>");
}
public void EndTableBody()
{
_sb.Append("</tbody>");
}
}
public class Row : IDisposable
{
private StringBuilder _sb;
private bool _isHeader;
public Row(StringBuilder sb, bool isHeader = false)
{
_sb = sb;
_isHeader = isHeader;
if (_isHeader)
{
_sb.Append("<thead>\n");
}
_sb.Append("\t<tr>\n");
}
public void Dispose()
{
_sb.Append("\t</tr>\n");
if (_isHeader)
{
_sb.Append("</thead>\n");
}
}
public void AddCell(string innerText)
{
_sb.Append("\t\t<td>\n");
_sb.Append("\t\t\t"+innerText);
_sb.Append("\t\t</td>\n");
}
}
}
Then you can define your table using:
StringBuilder sb = new StringBuilder();
using (Html.Table table = new Html.Table(sb))
{
foreach (var invalidCompany in mailMessageObject.InvalidCompanies)
{
using (Html.Row row = table.AddRow())
{
row.AddCell(invalidCompany.BusinessName);
row.AddCell(invalidCompany.SwiftBIC);
row.AddCell(invalidCompany.IBAN);
}
}
}
string finishedTable = sb.ToString();
It is a decent approach, and just 'what it takes' to output something as complicated as HTML - unless you want to do it using plain strings (which is just as messy, if not worse).
One improvement: do not use the same cell object multiple times, you run the risk of getting incorrect output. Improved code:
row.Cells.Add(new HtmlTableCell { InnerText = invalidCompany.BusinessName });
row.Cells.Add(new HtmlTableCell { InnerText = invalidCompany.SwiftBIC });
row.Cells.Add(new HtmlTableCell { InnerText = invalidCompany.IBAN });
Of course you can also create your own helpers for creating cells, for creating a row full of cells, etc. There are also good libraries for this, e.g. see https://www.nuget.org/packages/HtmlTags/.
I think maybe you can add a function to get all the properties from your object. And then just iterate over them. Also you can create a list of properties that need to be displayed in your message.
private static PropertyInfo[] GetProperties(object obj)
{
return obj.GetType().GetProperties();
}
// -------
foreach (var invalidCompany in mailMessageObject.InvalidCompanies)
{
var properties = GetProperties(invalidCompany);
foreach (var p in properties)
{
string name = p.Name;
if(propertiesThatNeedToBeDisplayed.Contains(name)
{
cell.InnerText = p.GetValue(invalidCompany, null);
row.Cells.Add(cell);
table.Rows.Add(row);
}
}
}
I am calling a custom action from my view with a $.post and sending a couple user generated parameters with it:
$("#submitReport").click(function () {
var carData = $("#car-select").val();
var bikeData = $("#bike-select").val();
if (carData && bikeData !== null) {
$.post('/Reporting/ExportToExcel', $.param({ carData: carData, bikeData: bikeData }, true), function(data) {
console.log(data);
});
}
});
Csv Action Result:
[HttpPost]
public CsvActionResult ExportToExcel(string[] carData, string[] bikeData)
{
var dt = new DataTable();
// Add all the stuff into the datatable
return new CsvActionResult(dt) { FileDownloadName = "MyReport.csv" };
}
And the most important part, the CsvActionResult class:
public sealed class CsvActionResult : FileResult
{
private readonly DataTable _dataTable;
public CsvActionResult(DataTable dataTable)
: base("text/csv")
{
_dataTable = dataTable;
}
protected override void WriteFile(HttpResponseBase response)
{
var outputStream = response.OutputStream;
using (var memoryStream = new MemoryStream())
{
WriteDataTable(memoryStream);
outputStream.Write(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
}
}
private void WriteDataTable(Stream stream)
{
var streamWriter = new StreamWriter(stream, Encoding.Default);
WriteHeaderLine(streamWriter);
streamWriter.WriteLine();
WriteDataLines(streamWriter);
streamWriter.Flush();
}
private void WriteHeaderLine(StreamWriter streamWriter)
{
foreach (DataColumn dataColumn in _dataTable.Columns)
{
WriteValue(streamWriter, dataColumn.ColumnName);
}
}
private void WriteDataLines(StreamWriter streamWriter)
{
foreach (DataRow dataRow in _dataTable.Rows)
{
foreach (DataColumn dataColumn in _dataTable.Columns)
{
WriteValue(streamWriter, dataRow[dataColumn.ColumnName].ToString());
}
streamWriter.WriteLine();
}
}
private static void WriteValue(StreamWriter writer, String value)
{
writer.Write("\"");
writer.Write(value.Replace("\"", "\"\""));
writer.Write("\",");
}
}
When I look in the console, I can see that the data is being returned, but it doesn't prompt a file download in the browser. So I actually need to do something with the data when it is returned. I thought it would prompt a file download automatically.
Any help would be appreciated.
So I have this problem. I have Project class with Name and Resource properties. I have DataSet and I want to set my Resource property values(of type Dictionary) from the DataSet. And tha's where I struggle.
Any ideas how I could solve this problem? Preferably not using LINQ/Lambdas.
I'm getting Invalid Initializer member declarator error. I hope there is a proper way to do it so error is not relevant. Thanks in advance!
public class FakeDataset
{
public static System.Data.DataTable TTable()
{
DataTable table = new DataTable("Resources");
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Resource", typeof(string));
table.Columns.Add("Value", typeof(string));
table.Rows.Add("Project", "Resource1", "11");
table.Rows.Add("Project", "Resource2", "12");
table.Rows.Add("Project", "Resource3", "9");
table.Rows.Add("Project22", "Resource1", "1");
table.Rows.Add("Project22", "Resource2", "2");
return table;
}
public static DataSet CreateDataset()
{
DataSet dataset = new DataSet("ProjectDataset");
dataset.Tables.Add(TTable());
return dataset;
}
}
public class Project
{
public string Name { get; set; }
public Dictionary<string, string> Resource { get; set; }
}
class Program
{
public static void Main()
{
var dataset = FakeDataset.CreateDataset();
var projectList = new List<Project>();
foreach (DataTable table in dataset.Tables)
{
foreach (DataRow dataRow in table.Rows)
{
projectList.Add(new Project { Name = Convert.ToString(dataRow["Name"]), Resource.Add(dataRow["Resource"].ToString(), dataRow["Value"].ToString()) });
}
}
}
}
Writing your for loop like this will solve the issue
foreach (DataTable table in dataset.Tables)
{
foreach (DataRow dataRow in table.Rows)
{
var dict = new Dictionary<string, string>();
dict.Add(dataRow["Resource"].ToString(), dataRow["Value"].ToString());
projectList.Add(new Project { Name = Convert.ToString(dataRow["Name"]), Resource = dict });
}
}
Or, using collection initialize syntax
foreach (DataTable table in dataset.Tables)
{
foreach (DataRow dataRow in table.Rows)
{
projectList.Add(new Project {
Name = Convert.ToString(dataRow["Name"]),
Resource = new Dictionary<string, string> { { dataRow["Resource"].ToString(), dataRow["Value"].ToString() } } }
);
}
}
But, do you really need Resource as a Dictionary<,> ? As of now, it will contain only one entry per Project class. Maybe you just need two string properties instead?
I am going to create print page in wpf with *.rdlc.
For this , i create a class(following is this codes).
I bind the class to report but when i run the program , following message occurs :
A data source instant has not been supplied for data source 'dataset1'
class rpt_insurance
{
private string _insurance;
private int _count_print;
private int _sum_tariff;
private int _lot_org;
public string insurance
{
get { return _insurance; }
set { _insurance = value; }
}
public int count_print
{
get { return _count_print; }
set { _count_print = value; }
}
public int sum_tariff
{
get { return _sum_tariff; }
set { _sum_tariff = value; }
}
public int lot_org
{
get { return _lot_org; }
set { _lot_org = value; }
}
public DataTable report_insurance(string from_date,string to_date)
{
using (doctorEntities de = new doctorEntities())
{
var print = (from Table_infobase_print tip in de.Table_infobase_print
where tip.Print_date.CompareTo(from_date) > 0 && tip.Print_date.CompareTo(to_date) < 0
select tip).ToList();
var insurance = (from Table_insurance_org tio in de.Table_insurance_org
select tio).ToList();
List<rpt_insurance> lri = new List<rpt_insurance>();
foreach (var insurance_row in insurance)
{
rpt_insurance ri = new rpt_insurance();
int number = 0;
foreach (var print_row in print)
{
if(print_row.insurance_org==insurance_row.org_name)
{
number++;
ri.insurance = print_row.insurance_org;
ri.count_print = number;
ri.sum_tariff = ri.sum_tariff + print_row.sum_tariff;
ri.lot_org=lot_org+(print_row.sum_tariff-print_row.sum_lot_patient);
}
}
if (ri.insurance != null)
{
lri.Add(ri);
}
}
DataTable dt = new DataTable();
dt = new DataTable();
dt.Columns.Add("cinsurance");
dt.Columns.Add("ccount_print");
dt.Columns.Add("csum_tariff");
dt.Columns.Add("clot_org");
for (int i = 0; i < lri.Count; i++)
{
DataRow dr = dt.NewRow();
dr["cinsurance"] = lri[i].insurance;
dr["ccount_print"] = lri[i].count_print;
dr["csum_tariff"] = lri[i].sum_tariff;
dr["clot_org"] = lri[i].lot_org;
dt.Rows.Add(dr);
}
return dt;
}
}
}
You need to supply the dataset to your report. Something like:
viewer.LocalReport.DataSources.Add(new ReportDataSource("dataset1", dataTable));
Edit: based on your comment
private void Window_Loaded(object sender, RoutedEventArgs e)
{
var dataTable = report_insurance(fromDate, toDate);
viewer_insurance.LocalReport.ReportPath = "E:\\desktop\\Doctor\\Project\\Doctor\\Doctor\\rinsurance.rdlc";
viewer_insurance.LocalReport.DataSources.Add(new ReportDataSource("dataset1", dataTable);
viewer_insurance.RefreshReport();
}
You really can't get around the need to call your data retrieval method AND send that data through to the report.