I am currently writing an application where I am getting data from the DB and passing it to the object which will later be used to send the data off else where. The issue I am having in testing is that the data doesn't hold in the object as when it is used later, I get null value errors. I know we can store these in sessions, but I also know you can use objects and have done it before at previous jobs, but do not recall what I am missing to maintain the information. Would I need to pass the object(s) from method to method until the job is done?
the first sample here shows where it is prepping the object.
public void FtpInitialize()
{
_LogController.LogToFile(ValidateMessage.BeginInitialization);
//Loading FTPClient object with ClientInfo Object data we got from DataBase. FTPClient object is the object that sends the data.
_LogController.FTPTraceLogToFile();
ClientInfo = _RepositoryController.GetClientInfo(ClientInfo);
if (ClientInfo == null)
ClientInfo.ClientDataExists = false;
else
{
FTPClient.Host = ClientInfo.Host;
FTPClient.Port = ClientInfo.Port;
FTPClient.EncryptionMode = FtpEncryptionMode.Explicit;
FTPClient.Credentials = new NetworkCredential(ClientInfo.UserName, ClientInfo.Password);
FTPClient.DataConnectionType = FtpDataConnectionType.EPSV; //according library documentation, auto passive is broken as of 10/20/2016
FTPClient.EnableThreadSafeDataConnections = ClientInfo.EnableThreadSafeConnection;
FTPClient.DataConnectionConnectTimeout = ClientInfo.DataConnectionTimeout;
FTPClient.DataConnectionReadTimeout = ClientInfo.DataReadTimeout;
FTPClient.ConnectTimeout = ClientInfo.ConnectionTimeout;
FTPClient.ReadTimeout = ClientInfo.ReadTimeout;
FTPClient.SocketPollInterval = ClientInfo.SocketPollInterval;
FTPClient.SocketKeepAlive = ClientInfo.KeepSocketAlive;
FTPClient.ValidateCertificate += new FtpSslValidation(OnValidateCertificate);
_LogController.LogToFile(ValidateMessage.ClientDataLoaded);
ClientInfo.ClientDataExists = true;
}
}
then below when I hit this part, it shows as null
public bool SendData()
{
short errorCount = 0;
using (FTPClient)
{
if (ClientInfo.ClientDataExists)
{
This looks like you are using local variables in your methods. This is why the data "disappears".
For example if you are pulling data from your database you should have some kind of model class and container so that the data can persist until you are done with it.
EX: You have a database that contains information on people (name, dob, etc).
You should have a class that defines person and possibly a List to store said people. You call your database and pull X person objects into your List variable. You then can pass your List into the methods. Note: You can ditch the List (or whatever collection you use) if you are doing it one at a time.
The implementation of this really depends on how you want the objects to persist. If you know you will only pull one person object at a time you can declare var databasePerson from the database. Use the List if you will be pulling more information and then pop off the object when your are down with it.
Hope that helps.
Related
Here is my current problem. Lets say I have a DBConext for Customers called CustomerContext and on for Employees called EmployeeContext. I have them in two different DBContexts to keep it smaller and simplified. When I want to create a new customer, I call my Customers BLL(Business Logic Layer) which will in turn create a new instance of the CustomerContext. Now that context will be passed to a other related BLLs to verify the information and add their own records to the context to be inserted. when a context is passed into a BLL, that BLL will not save the changes to the context, the Parent level procedure will do that.
This works fine except when I pass the context to the Notes BLL. Here If I define the context as CustomerContext I am okay, but I need to also use this with EmployeeContext. How can I pass the Context in and determine which one to use at runtime? I tried passing it in as an object, but then if I try to add it to the table, I get object does not contain a definition for Note. Any suggestions would be greatly appreciated.
Here is a sample of what I want it to do, but I get an error on the moContext.Notes.Add(oNote); line, because its an object and not the context. moContext could be either CustomerContext or EmployeeContext.
object moContext;
bool mbContextCreatedLocal;
public NotesDAL(ref object pContext)
{
moContext = pContext;
mbContextCreatedLocal = false;
}
public void InsertNote(Note pNote)
{
Note oNote = null;
oNote = new Note()
{
Note = pNote.Note.Trim(),
NoteCategoryID = pNote.NoteCategoryID,
Title = (string.IsNullOrEmpty(pNote.Title) ? null : pNote.Title.Trim()),
};
moContext.Notes.Add(oNote);
if (mbContextCreatedLocal )
{
moContext.SaveChanges();
}
}
I am trying to devise a good way to perform updates to a SQL Server database using WCF Data Services and Entity Framework. The problem I'm having is that it seems overly complex to perform update, delete, and insert operations using the service.
I'll use typical Customer / Invoices scenario to help explain my current approach. I'm using WPF MVVM for the application. My view model contains a customer object that receives updates from the user. When saving, I pass the customer object to the service. The service must then load the customer object, transfer the property values from the updated customer, then perform the save.
Something like this:
public static int SaveProgram(Customer entity)
int returnValue = 0;
// Setup the service Uri
Uri serviceUri = new Uri(Properties.Settings.Default.DataUri);
try
{
// Get the DB context
var context = new DevEntities(serviceUri);
Customer dbCustomer;
if (entity.CustomerId == 0)
{
dbCustomer = new Customer();
context.AddToCustomers(dbCustomer);
}
else
{
dbCustomer = context.Customers.Where(p => p.CustomerId == entity.CustomerId).FirstOrDefault();
}
if (dbCustomer != null)
{
dbCustomer.StatusId = entity.StatusId;
dbCustomer.FirstName = entity.FirstName;
dbCustomer.LastName = entity.LastName;
dbCustomer.Address = entity.Address;
...
}
context.UpdateObject(dbCustomer);
// Submit Changes
DataServiceResponse response = context.SaveChanges(SaveChangesOptions.Batch);
// Check for errors
...
returnValue = response.Count();
}
... Catch exceptions
return returnValue;
}
Is it really necessary to go through all of this? It seems there should be an easier way.
Adding an invoice requires something like this:
var newInvoice = Invoice.CreateInvoice(0, customerId, etc...);
context.AddRelatedObject(dbCustomer, "Invoices", newInvoice);
Having already added a new invoice to the Customer.Invoices collection, this seems cumbersome.
Deleting an invoice is even worse. To delete an invoice I have to compare the invoices collection from the database with that of the passed in entity. If I cannot find a database version of the invoice in the entity.Invoices collection, then I know it should be deleted.
I have the feeling that I must not be approaching this correctly.
I use the EF 3.5 in VS 2010. I have a method which returns a struct. In the struct there is an object armatuur. When the struct is returned i want to access the related objects from the armatuur instance.
However
the method returning the struct:
public LampPostDetail getLamppostInfo(int id)
{
LampPostDetail lpd;
lpd.xPos = 0;
lpd.ypos = 0;
lpd.armatuur = new Armatuur();
//get the info from object
using (var db = new OvisionDBEntities())
{
var objects = from o in db.Objects
where o.ObjectId == id
select o;
foreach (OVSL.Data.Object o in objects)
{
lpd.xPos = o.XCoordinatie;
lpd.ypos = o.YCoordinatie;
lpd.armatuur = o.Armatuur; //which is a table in my db
}
return lpd;
}
}
struct:
public struct LampPostDetail
{
#region [ Data Members (14)]
//lamppost info
public double? xPos;
public double? ypos;
//a lamppost can have several armaturen
public OVSL.Data.Armatuur armatuur; //is a table in my db
#endregion [ Data Members ]
}
when doing this in my client:
LampPostDetail lpd = client.getLamppostInfo(id);
string brand = lpd.armatuur.producer.name; //producer is related object of armatuur
I get a ObjectDisposedException. I understand that this happens because the LampPostDetail object is disposed after the using block is finished. But how do i get this to work? Retrieving all information I need (like brand name e.g.) before I return it to the client is not not an option.
The only thing that gets disposed here is the OvisionDBEntities context. After that, no lazy loading is possible. How to deal with that? In fact your question is: what can you do to feed a client with all data that are potentially required for user actions at any time? I see three or four options:
The standard way to enable access to navigation properties of entities after context disposal is calling Include: from o in db.Objects.Include("Armatuur.Producer")... But that's clearly not an option for you.
Let the context live and rely on lazy loading to fetch data on demand. This may be an option for you. But long-lived contexts may cause problems like gradually declining performance as the internal change track record grows, and stale cached data giving rise to refresh/reload statements scattered all over the place.
In stead of navigation properties/lazy loading fetch data on demand from a service/repository layer that uses context instances per call. I think this option could work well for you.
More a functional than a technical option: design use cases that can do with less data (so that Include may suffice after all). No one can take in a grid with thousands of rows and tens of columns. Well-designed user interaction can drastically reduce the amount of data that is pumped into a client (and I'm only at the beginning of getting this).
Its not you LampPostDetail that is getting disposed, it is the Armatuur object you retrieved from the database that it references, or an object that Armatuur is referencing.
I can see two options to getting around this. The first is to make the Entity context an optional parameter to your getLamppostInfo info method. Since you are using 3.5 you will have to do an overload to keep the orignal functionality:
public LampPostDetail getLamppostInfo(int id,OvisionDBEntities context)
{
...
try
{
OvisionDBEntities db;
if (context == null)
db = new OvisionDBEntities();
else
db = context;
...
}
finally
{
if (context == null && db != null)
db.Dispose() // or close maybe
}
retun lpd;
}
// Overloaded function to keep orignal functionality (C# 3.5 does not have
// optional parameters)
public LampPostDetail getLamppostInfo(int id)
{
return LampPostDetail(id,null)
}
Now you can call it as:
using (var db = new OvisionDBEntities())
{
LampPostDetail lpd = client.getLamppostInfo(id,db);
string brand = lpd.armatuur.producer.name;
}
And your objects will still exist when you try to reference them.
The other option is to detach your referenced objects from the entity context, before disposing of it.
db.Detach(o.Armatuur);
However, I don't believe that detaches any objects references by that object. So you would have to interate the reference trees and detach thoes objects as well.
I am developing a c# application, in which the server gets requests from many clients at a time. Each client also gets their data from different databases. In this situation sometimes data leakage is happening, means clients get data from an incorrect database. Say for example client1 should get data from db1 and client2 gets data from db2. Instead they get data from opposite databases; client1 gets from db2 and client2 gets from db1.
I am adding the code below where it collects the data.
public string List()
{
Response.ContentType = ContentType.Xml;
try
{
ThingzFilter filter = null;
Dictionary<string, string> parameters = new Dictionary<string, string>();
if (Id!="")
{
// get parameters from http request
foreach (HttpInputItem param in Request.Param)
parameters.Add(param.Name, param.Value);
setServerURLs();
//Request.Clear();
if (Request.QueryString["lang"].Value != null)
{
ThingzDB.TzThing.get_language = Request.QueryString["lang"].Value.ToString();
}
else
{
ThingzDB.TzThing.get_language = SessionDatabase.DefaultLanguage;
}
}
ThingzDatabase db = SessionDatabase;
langStr = db.Language;
// this is run if there was no ID supplied
// which means we want all items of all types
if (Id == "")
{
if (Request.AcceptTypes == null)
{
//TypeController.session_id = Request.QueryString["sessionid"].Value;
jobs.Add(Request.QueryString["sessionid"].Value);
if (nextJobPos > jobs.Count - 1)
return "";
else
{
TypeController.session_id = jobs[nextJobPos];
nextJobPos++;
langStr = SessionDatabase.Language;
}
filter = new AllThingzFilter(SessionDatabase, parameters, langStr);
TypeController.session_id = "";
filter.Execute();
}
In this server is console application and clients are windows where the site names , means the databse names are mentioned.
Please give me a solution to overcome this issue.
Without precisely knowing how SessionDatabase is scoped (from the name it seems to be a session variable) or whether it's implementation is a property that does some kind of complex logic, I would guess you have two problems:
Storing the value at the wrong scope with multiple clients accessing it
Using db and SessionDatabase interchangeably in your code.
For the latter, I would suggest db = SessionDatabase once at the top of the code (making sure that SessionDatabase was the right thing for that client, and then using db for the rest of the method.
I'm using .NET 3.5 and I need some help with how to hold a data object when you transfer between different pages.
This is my setup:
I have a four step registration where each step includes its own web page. I want to be able to hold a object in memory between the pages without saving it to the database. Each page will add something to this object.
Just for the ease of it, lets say I have a object like
public class MyObject
{
private int myNumber;
private String myName;
private List<Person> myFriends; //Person is simply a class that has a Strign name with getter and setters.
public MyObject()
{
myFriends = new List<Person>();
}
public void setMyNumber(int i){
myNumber = i;
}
public void setMyName(String n)
{
myName = n;
}
public void setMyFriends(List<Person> li)
{
myFriends = li;
}
public void addFriend(Person p)
{
myFriends.Add(p);
}
}
When I then get to the last page and have collected all the data, then I will commit it to my database. What is the best way to do this in c#? Any nice links or samples would be great!
You can use session/cookie to hold the data.
See the sample code of how to use session below.
How to: Save Values in Session State
string firstName = "Jeff";
string lastName = "Smith";
string city = "Seattle";
Session["FirstName"] = firstName;
Session["LastName"] = lastName;
Session["City"] = city;
How to: Read Values from Session State
string firstName = (string)(Session["First"]);
string lastName = (string)(Session["Last"]);
string city = (string)(Session["City"]);
Reference:
http://msdn.microsoft.com/en-us/library/ms178581.aspx#CodeExamples
Http is stateless protocol, you can use Session variable and store the object of Person into Session["variable"] = [Object] and access it on the last page.
Store the data in session for example
Session["Test"] = "Hello World"; //store in session
string str = (string)Session["Test"];//retrieving from session
So, once the value is stored in session, it can be retrieved from other pages.
If you're using in-process session state mode, you'd be fine storing such object in session.
Otherwise, you'd need to taylor some custom approach, because SQL and StateServer modes will be serializing and unserializing that object every time you want to retrieve and store it - less optimal -. Use session state, even in this operational modes if your object is as simple as having strings, integers or any other basic type (that wouldn't be a problem in terms of performance).
I guess if it's some wizard you won't need to store large data, so you could be fine with session state.
Perhaps you want to store text, or some other big things, and I believe best solution would be take a look to Windows Workflow Foundation which has a persistent storage API so you can manage a workflow (like your wizard) and save some state after finishing some step, but I repeat, this could be a good overkill. Take this advice if this user registration wizard needs a lot of information.