In my application we have an aspx page frmwebform1.
This page has a static method GetmyData() which calls a helper class HelperClass
But the problem with the code is that when we call the method GetHelperData(), in this
helper class it instantiates frmwebform1 in order to get its method FillGrid().
The problem is when it instantiates frmwebform1 we are loosing entityId and entityType values.
Is there any way I could call the method FillGrid() without instantiating the frmwebform1 page. Unfortunately I cannot make the FillGrid() method as static, as it
will compromise our data.
Thanks for you help in advance.
//frmwebform1.aspx.cs
public partial class frmwebform1 : System.Web.UI.Page
{
string entityId;
string entityType;
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["entityId"] != null)
{
entityType = Request.QueryString["entityType"].ToString().ToUpper();
entityId = Request.QueryString["entityId"].ToString();
}
if (!IsPostBack)
{
grdMygrid.DataSource = FillGrid();
grdMygrid.DataBind();
}
}
public DataTable FillGrid()
{
string server = HttpContext.Current.Session["Server"].ToString();
string database = HttpContext.Current.Session["Database"].ToString();
string usrID =HttpContext.Current.Session["user_ID"].ToString();
Data tr = new getData(server, database, usrID);
DataTable dt = tr.getAllEntities(entityId);
return dt;
}
[WebMethod] //AJAX page method
public static List<class1> GetmyData()
{
HelperClass helper = new HelperClass();
return helper.GetHelperData();
}
}
//Second Class
public class HelperClass
{
public List<class1> GetHelperData()
{
frmwebform1 form1 = new frmwebform1();
DataTable dt = form1.FillGrid();
List<class1> list = new List<class1>();
class1 item;
foreach (DataRow dr in dt.Rows)
{
item = new TaxHistory();
item.txr_guid = dr["txr_guid"].ToString();
item.Amount = string.Format("{0}", dr["Amount"]);
item.Email = dr["EmailAddress"].ToString();
item.Date = dr["date"].ToString();
item.user = dr["user"].ToString();
list.Add(item);
}
return list;
}
}
Extract that method from the Page class because it clearly should not be there as it seems to be of a different responsibility:
How do we determine an object's responsibility in OOP?
Create a static class and put that method there.
Make the FillGrid method static.
Rather than having method that fetches data from the db in page class and calling it from some other class is not good thing. If you know layered architecture, you should move that method to Data Access Layer and call that method from page method, which will return you DataTable.
I hope it makes sense :)
I used PageMethods from Javascript. which solved my issue.
Thanks for all your answers.
Related
I am creating a helper class for my MVC application. This class will contain static methods that will pull information the first time the user logs into the system.
I have created two methods that will return lists like list of countries and list of languages. I don't want to execute this every time but save results of first call and return it for subsequent calls.
public static List<Languages> GetLanguages()
{
using (var db = new MCREntities())
{
var languages = db.spGetLanguages(0);
return Mapper.Map<List<Languages>>(languages);
}
}
public static List<Countries> GetCountries()
{
using (var db = new MCREntities())
{
var countries = db.spGetAllCountries("");
return Mapper.Map<List<Countries>>(countries);
}
}
Inside your class you can have static list which would hold Languages anly first time would try to access database.
private static List<Languages> _languages = null;
public static List<Languages> GetLanguages()
{
if(_languages == null){
using (var db = new MCREntities())
{
var languages = db.spGetLanguages(0);
_languages = Mapper.Map<List<Languages>>(languages);
}
}
return _languages;
}
Alternatively, you can implement cache
i would say create a class with the required properties liek
public static class CurrentSession{
List<Languages> lang{get;set;}
List<Countries> countries{get;set;}
}
and in global.asax file
protected void Application_Start()
{
//.........predefined codes
CurrentSession.lang = GetLanguages();
CurrentSession.Countries =GetCountries();
First Look at my code
namespace HealthClub
{
public partial class frmTrainerMaster : Form
{
DataTable dt = new DataTable();
frmHome Home = new frmHome();
public frmTrainerMaster()
{
InitializeComponent();
}
}
private void frmTrainerMaster_Load(object sender, EventArgs e)
{
FillValues("UserNameText");
}
public void FillValues(string UserName)
{
DataTable DT;
SqlCommand cmd = new SqlCommand();
try
{
cmd.Connection = Connections.Connection[UserName];
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "TrainerMaster_pro";
cmd.Parameters.AddWithValue("Option", "FillValues".Trim());
if (Connections.Connection[UserName].State == ConnectionState.Closed)
Connections.Connection[UserName].Open();
SqlDataAdapter adp = new SqlDataAdapter(cmd);
DT = new DataTable();
adp.Fill(DT);
lblId___.Text = DT.Rows[0][0].ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
cmd.Parameters.Clear();
cmd.Dispose();
Connections.Connection[UserName].Close();
}
}
}
Now I am calling FillValues() from another class like this
class AnotherClass
{
public void TestMethod(string FormName)
{
Type tp = Type.GetType("HealthClub." + FormName);
object myobj = Activator.CreateInstance(tp);
MethodInfo method = myobj.GetType().GetMethod("FillValues");
object[] parametersArray = new object[] { UserName };
method.Invoke(myobj, parametersArray);
}
}
If you look at the FillValues(), I am assigning the database value to a label. When I am calling it in my first class in page load it's working fine.
But when I am Invoking the medthod from second class, Method invokes but database value does not assign to the label.
What extra effort I need to do ?
There is a class and there is an instance. This is very basic concept you need to understand (not just in C#, but in any objective-oriented language).
// class example
class FrmTrainerMaster { public int SomeProperty { get; set;} }
When you create new instance:
// creates one window
var frmTrainerMasterInstanceOne = new FrmTrainerMaster();
frmTrainerMasterInstanceOne.SomeProperty = 1;
// creates second window
var frmTrainerMasterInstanceTwo = new FrmTrainerMaster();
frmTrainerMasterInstanceTwo.SomeProperty = 2;
Instances are SEPARATE - so at this point querying
// will return 1
Console.Out.WriteLine(frmTrainerMasterInstanceOne.SomeProperty);
// will return 2
Console.Out.WriteLine(frmTrainerMasterInstanceTwo.SomeProperty);
With reflection var myobj = Type.GetType("HealthClub.FrmTrainerMaster"); is equal to var myobj = new FrmTrainerMaster(); so by doing anything with myobj, you still can't affect frmTrainerMasterInstanceOne or frmTrainerMasterInstanceTwo.
What do you need is actually method how to pass reference to instance (of FrmTrainerMaster class) to place where you need it (lets call it AnotherForm), there is no magic list of all instances for given class unless you explicitly build it.
public partial class FrmTrainerMaster : Form
{
public void FillValues(string userName) { ... }
}
One way is via constructor injection (generally proffered - since at time when object (AnotherForm) is constructed you have it in valid state (i.e. with all dependencies initialized).
public class AnotherForm : Form {
private readonly FrmTrainMaster _frmTrainMaster;
public AnotherForm(FrmTrainMaster frmTrainMaster) {
if (frmTrainMaster == null) {
throw new ArgumentNullException(nameof(frmTrainMaster));
}
_frmTrainMaster = frmTrainMaster;
}
}
Or via setter injection:
public class AnotherForm : Form {
private FrmTrainMaster _frmTrainMaster;
public FrmTrainMaster MasterForm { set { _frmTrainMaster = value; } }
}
Either way the reflection is not necessary at all. At any place in your AnotherForm you can just call
class AnotherForm : Form {
...
public void FooMethodThatCallFillValues() {
_frmTrainMaster.FillValues("...");
}
}
When trying to compile my c# windows app I am getting the following error:
The name 'GetActiveLB' does not exist in the current context
Here's the code that calls that function:
using F5LTMMaintenance;
......
private void btnLBSetA_Click(object sender, EventArgs e)
{
List<string> range = GetActiveLB();
foreach (string item in range)
{
// Do something with item
}
}
Then I have a class with the following:
namespace F5LTMMaintenance
{
public class F5LTM<T>
{
public List<T> GetActiveLB()
{
var client = new RestClient("mylb.domain.local");
var request = new RestRequest("mgmt/tm/cm/failover-status", Method.GET);
var queryResult = client.Execute<List<T>>(request).Data;
return queryResult == null ? new List<T>() : queryResult;
}
}
}
The GetActiveLB function does exist, its a public function so why am I getting this error? Any help would be appreciated.
It has to be used with an instance of F5LTM<T>.
e.g.:
var f5ltm = new F5LTM<string>();
List<string> range = f5ltm.GetActiveLB();
Alternatively, if you declare it as static like this:
public class F5LTM //not generic here
{
public static List<T> GetActiveLB<T>() //generic here and static
{
//unchanged
}
}
Usage:
List<string> range = F5LTM.GetActiveLB<string>();
Or with C# 6 using static syntax:
using static F5LTMMaintenance.F5LTM; //at top of file
List<string> range = GetActiveLB<string>();
This is as close as you can get to the code you posted.
Yes it's a public function but it's defined inside a different class than your calling event handler class. You need to create a instance of your class F5LTM<T> and on that instance call your method GetActiveLB() rather like
private void btnLBSetA_Click(object sender, EventArgs e)
{
F5LTM<Type> test = new F5LTM<Type>();
List<string> range = test.GetActiveLB();
You will need an instance of your F5LTM class (say typF5LTM), to be able to call typF5LTM.GetActiveLB(). Or you need to make GetActiveLB a static function to be able to call it without an instance like F5LTM.GetActiveLB();
As another poster pointed out, you have to call the method on the class.
F5LTM<string> listItems = new F5LTM<string>();
List<string> range = listItems.GetActiveLB();
I have the following implementation that works for converting rows in a DataTable to a List<T>. The IDataItem interface just contains the SetData method that takes in a single DataRow object.
public class GroupedData<T> : List<T> where T : IDataItem, new()
{
public GroupedData(DataTable table)
{
for (int i = 0; i < table.Rows.Count; i++)
{
DataRow row = table.Rows[i];
var newItem = new T();
newItem.SetData(row);
Add(newItem);
}
}
}
These are the properties in the class I am trying to assign values to:
public class Details
{
public List<AuditData> AuditEntries { get; set; }
public AuditMethodSummaryData AuditMethodSummaryData { get; set; }
}
With the GroupedData class, I can execute the following to populate AuditEntries:
var returnData = new Details();
returnData.AuditEntries = new GroupedData<AuditData>(dataSet.Tables[TableNames.AuditDetails]);
For the second property, AuditMethodSummaryData. I need to assign a single object instead of a List. I can't figure out how to create another class that can perform the function.
Note - I still need to pass in a DataTable. However, the data table will only ever contain a single row (due to the way the system works).
The only solution I've came up with is below. I just want to see if there is a better solution:
public class SingleData
{
public static T GetItem<T>(DataTable table) where T : IDataItem, new()
{
if (table.Rows.Count >= 1)
{
DataRow row = table.Rows[0];
var newItem = new T();
newItem.SetData(row);
}
}
}
What I don't like is that i've moved the constraint from the class to the method. Is there a way I can keep it on the class? Avoiding the static method.
Well, for the single item you don't need generics at all:
public class SingleItem : IDataItem
{
public SingleItem(DataTable table)
{
if (table.Rows.Count >= 1)
{
var row = table.Rows[0];
SetData(row);
}
else
{
throw new ArgumentException("No rows.", "table");
}
}
public abstract void SetData(DataRow row);
}
public AuditMethodSummaryData : SingleItem
{
public AuditMethodSummaryData(DataTable table) : base(table)
{}
public override void SetData(DataRow row) { /*...*/ }
}
This still doesn't solve case when you need to return null for zero rows. In that case you have to use factory pattern - which can be implemented in various ways - static method is the easy and I think decent approach for your case; if you don't want to have static method you have to create factory class instead like:
public class DataItemFactory<T> where T : IDataItem, new()
{
private readonly DataTable m_Table;
public DataItemFactory(DataTable table)
{
m_Table = table;
}
public T Create()
{
T result = default(T);
if (m_Table.Rows.Count > 1)
{
result = new T();
result.SetData(m_Table.Rows[0]);
}
return result;
}
}
With usage like:
returnData.AuditMethodSummaryData =
new DataItemFactory<AuditMethodSummaryData>(table).Create();
I have a class name OFCls which has a method call getOF()
I want to use that method in another class method.
public void Display()
{
var oOF = new OFCls();
dataGridView1.DataSource = OFCls.getOF.Tables(0);
}
I get the error MyProject.OFCls.getOF() is a method which is not valid in the given context.
What should I do to call a class method! Thank you heaps
You seem to be missing brackets
public void Display()
{
var oOF = new OFCls();
dataGridView1.DataSource = OFCls.getOF().Tables[0];
}
or if it is not static
public void Display()
{
var oOF = new OFCls();
dataGridView1.DataSource = oOF .getOF().Tables[0];
}
If getOF is a method, call it:
OFCls.getOF().Tables(0);