dyarosh
asked on
How to override a method in a class that implements an interface in C#
I have a class that is compiled into its own DLL. The purpose of the class is to interface with a database that can be an ORACLE or SQL Server database. I created the class as public partial class DatabaseMethods : IDatabaseMethods. I'm including the class code here but have removed the methods that aren't needed for this question.
Now I have an app that wants to use the DatabaseMethods class but needs to provide its own version of the GetEFConnectionString Method.
How would I do that? If I create a new class that implements the Interface and implement the 2 methods in the interface, how do I get access to all of the private methods in the DatabaseMethods class? I need the class to be an interface so I can do Dependency Injection for my testing.
Here is what I have so far but don't konw how to tell it to implement the Interface also.
Any help is greatly appreciated!
namespace DatabaseMethodsClass
{
public interface IDatabaseMethods
{
string GetDatabaseConnection(int dbid);
string GetEFConnectionString();
}
public partial class DatabaseMethods : IDatabaseMethods
{
private string _serversxml;
public virtual string serversxml
{
get { return _serversxml; }
set { this._serversxml = @"file://PL-WLMSPTPV04/websites/i21/Includes/xml/Servers.xml"; }
}
private HttpContextBase _httpContext = null;
private CryptorEngine _CryptorEngine = null;
public DatabaseMethods() : this(new HttpContextWrapper(HttpContext.Current), new CryptorEngine()) { }
public DatabaseMethods(HttpContextBase hcb, CryptorEngine ce)
{
_httpContext = hcb;
_CryptorEngine = ce;
}
// Other methods removed to make this easier to read
public virtual string GetDatabaseConnection(int dbid)
{
// Servers.xml contains a list of all the servers Intranet Support Team Applications are deployed to;
// Also contains the Connection Strings for the Application Catalog application for each environment (DEV, UAT, PROD)
XmlDocument xmldoc = LoadServersXML(serversxml);
string host = DetermineHost();
int env = DetermineEnvironmentFromHost(host, xmldoc);
string appcatalogcs = GetAppCatalogConnectionString(env);
// Get Database record
AppCatalog_DBConnection db = new AppCatalog_DBConnection();
db = GetDBConnectionRecord(dbid, appcatalogcs, env);
return FormatConnectionString(db);
}
public virtual string GetEFConnectionString()
{
// Servers.xml contains a list of all the servers Intranet Support Team Applications are deployed to;
// Also contains the Connection Strings for the Application Catalog application for each environment (DEV, UAT, PROD)
XmlDocument xmldoc = LoadServersXML(serversxml);
string host = DetermineHost();
int envid = DetermineEnvironmentFromHost(host, xmldoc);
// Create EF Connection String based on environment
string EFConnectionString = "";
switch (envid)
{
case 1: // DEV
EFConnectionString = @"metadata=res://*/Models.AppCatalog.csdl|res://*/Models.AppCatalog.ssdl|res://*/Models.AppCatalog.msl;provider=System.Data.SqlClient;provider connection string='data source=servername;initial catalog=Catalog;persist security info=True;user id=username;password=password;multipleactiveresultsets=True;App=EntityFramework'";
break;
case 2: // UAT
EFConnectionString = @"metadata=res://*/Models.AppCatalog.csdl|res://*/Models.AppCatalog.ssdl|res://*/Models.AppCatalog.msl;provider=System.Data.SqlClient;provider connection string='data source=servername;initial catalog=Catalog;persist security info=True;user id=username;password=password;multipleactiveresultsets=True;App=EntityFramework'";
break;
case 3: // PROD
EFConnectionString = @"metadata=res://*/Models.AppCatalog.csdl|res://*/Models.AppCatalog.ssdl|res://*/Models.AppCatalog.msl;provider=System.Data.SqlClient;provider connection string='data source=servername;initial catalog=Catalog;persist security info=True;user id=username;password=password;multipleactiveresultsets=True;App=EntityFramework'";
break;
default:
// Throw error - AppCatalog environment doesn't exist in Servers.xml
throw new ValidationException(String.Format("AppCatalog Connection String does not exist for Environment {0} in Server Configuration File", envid));
}
return EFConnectionString;
}
}
public partial class AppCatalog_DBConnection
{
public int dbconnectionID { get; set; }
public string dbconnectionUserName { get; set; }
public string dbconnectionUnsecuredPassword { get; set; }
public string dbconnectionServer { get; set; }
public string dbconnectionPortNumber { get; set; }
public string dbconnectionServiceName { get; set; }
public string dbconnectionCatalog { get; set; }
public string dbconnectionSID { get; set; }
public int dbconnectionEnvironmentID { get; set; }
public int dbconnectionDatabaseID { get; set; }
public int dbconnectionServerTypeID { get; set; }
}
}
Now I have an app that wants to use the DatabaseMethods class but needs to provide its own version of the GetEFConnectionString Method.
How would I do that? If I create a new class that implements the Interface and implement the 2 methods in the interface, how do I get access to all of the private methods in the DatabaseMethods class? I need the class to be an interface so I can do Dependency Injection for my testing.
Here is what I have so far but don't konw how to tell it to implement the Interface also.
public class REF_DatabaseMethods : DatabaseMethods
{
public override string GetEFConnectionString()
{
// my override code
}
}
Any help is greatly appreciated!
ASKER
I appreciate your comments but need some clarification.
1. The DatabaseMethods Class (I will come up with a better name) purpose is to "create" (as you suggested) the Connection String for a database that would be used as a parameter into an OracleConnection object or SqlConnection object which takes a string as a parameter. That is why the the method returns a string. The information needed to create the connection string is stored in a database. The dbid parameter in the method call is used to determine which database record to retrieve for the information.
We have many applications and environments that those applications run in (i.e. DEV, UAT, PROD) which is why we don't store the connection strings in config files. We also don't want the sensitive information such as username and password stored in flat file config files.
With that said, based on your recommendations I would remove the Interface definition from the same file and assembly as the definition for the DatabaseMethods class and put it in the same assembly as the class that is consuming the DatabaseMethods object. Is that correct?
If the above is correct and the interface is declared in a separate assembly, how do I get the first assembly to compile since IDatabaseMethods isn't defined in the assembly?
If the Interface is defined in the Higher Assembly then every project that wants to use the DatabaseMethods object would have to know to define the interface which doesn't make sense to me.
I want to have one class that will have a method for creating the connection string and also a method to create the EF connection string. For the most part, creating the connection string won't need to be overridden unless we add a new database to our mix. However creating the EF Connection String will need to be overridden by each project that consumes the object that uses the EF.
So how do I structure the DatabaseMethods class so that it can be consumed by many applications? I apologize for my ignorance but we are in the process of converting all of our legacy classic asp applications to asp.net and I want to get the infrastructure setup using SOLID OOP which is new to our group.
1. The DatabaseMethods Class (I will come up with a better name) purpose is to "create" (as you suggested) the Connection String for a database that would be used as a parameter into an OracleConnection object or SqlConnection object which takes a string as a parameter. That is why the the method returns a string. The information needed to create the connection string is stored in a database. The dbid parameter in the method call is used to determine which database record to retrieve for the information.
We have many applications and environments that those applications run in (i.e. DEV, UAT, PROD) which is why we don't store the connection strings in config files. We also don't want the sensitive information such as username and password stored in flat file config files.
With that said, based on your recommendations I would remove the Interface definition from the same file and assembly as the definition for the DatabaseMethods class and put it in the same assembly as the class that is consuming the DatabaseMethods object. Is that correct?
VS Studio Project 1 (DatabaseProviderDevelopment.DLL)
namespace DatabaseProviderDevelopment
{
public class DatabaseMethods : IDatabaseMethods
{
public string GetDatabaseConnection(int dbid) { }
string GetEFConnectionString() {};
}
}
VS Studio Project 2 (Project.DLL)
namespace DatabaseConsumer
{
public interface IDatabaseMethods
{
string GetDatabaseConnection(int dbid);
string GetEFConnectionString();
}
}
If the above is correct and the interface is declared in a separate assembly, how do I get the first assembly to compile since IDatabaseMethods isn't defined in the assembly?
If the Interface is defined in the Higher Assembly then every project that wants to use the DatabaseMethods object would have to know to define the interface which doesn't make sense to me.
I want to have one class that will have a method for creating the connection string and also a method to create the EF connection string. For the most part, creating the connection string won't need to be overridden unless we add a new database to our mix. However creating the EF Connection String will need to be overridden by each project that consumes the object that uses the EF.
So how do I structure the DatabaseMethods class so that it can be consumed by many applications? I apologize for my ignorance but we are in the process of converting all of our legacy classic asp applications to asp.net and I want to get the infrastructure setup using SOLID OOP which is new to our group.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thank you for your insight and the links.
Open in new window
Now for the code smells:
1. An interface named database methods makes no sense. It's either a catch basin, then the methods belong to different interfaces. Or it is badly named, it does not transport the usage in its name.
2. Methods should never use the verbs Get and Set. Except they are property getter/setter methods. As we have properties in C#, use them instead in your interface declaration.
3. A connection (GetDatabaseConnection) is not a string. string as a return type makes no sense.
4. A better name: CreateDatabaseConnection.
5. You don't need virtual methods, as long as you don't want to override some of your methods.
6.
Open in new window
You're describing entities. Implement them. Use XML serialziation.7. Sounds like your server list should be also decoupled and injected.
8. Never hardcode connection strings. Use .config files instead of it.
9. switch() indicates often (really often) that you can and should use inheritance. See my sample above.
10.Your class AppCatalog_DBConnection does not represent a connection. It's a data transfer object (DTO, POCO), which holds the configuration information for a connection. Name it accordingly.
11. I would guess from your code, the setters of AppCatalog_DBConnection should be private.