How to ensure that interface implementations have a connection string, if supported by the database using code contracts

Imagine you have an interface like this:

public interface IPersonManager
{
     public void AddPerson(string name);
}

... and the implementation we will call DefaultPersonManager. Say we want to be sure that any implementation IPersonManagercannot give an empty or empty string as an argument AddPerson(string name). In this case, we are going to implement the contract class as follows:

[ContractClassFor(typeof(IPersonManager))]
public abstract class IPersonManagerContract : IPersonManager
{
   public void AddPerson(string name)
   {
       Contract.Requires(!string.IsNullOrEmpty(name), "Person name cannot be a null or empty string");
   }
}

... and we will decorate our IPersonManagerinterface with the attribute ContractClassAttribute:

[ContractClass(typeof(IPersonManagerContractClass))]
public interface IPersonManager
{
     public void AddPerson(string name);
}

We talked about DefaultPersonManager. It will look like this:

public class DefaultPersonManager
{
    private readonly List<string> _personNames = new List<string>();

    public void AddPerson(string name)
    {   
        // "name" argument will be verified by contract class!
        _personNames.Add(name);
    }
}

Good!

IPersonManager, DefaultPersonManager , AddPerson SQL (.. SQL Server, ...). DbBackedPersonManager.

DbBackedPersonManager , AddPerson DbBackedPersonManager:

public void AddPerson(string name)
{
     Contract.Requires(ConfigurationManager.ConnectionStrings["SomeConnectionStringId"] != null, "A connection string is required in your application/web configuration file");
}

: , AddPerson , Requires ( Q & A , , - -.).

, , ?

0
2

, IWithSqlDbBackend ( ...) :

public interface IWithSqlDbBackend
{
     string ConnectionString { get; }
     string ConnectionStringId { get; set; }
}

:

[ContractClassFor(typeof(IWithSqlDbBackend))]
public abstract class IWithSqlDbBackendContract : IWithSqlDbBackend
{
    public string ConnectionString
    {
        get 
        {  
            Contract.Requires(!string.IsNullOrEmpty(ConnectionStringId), "Connection string id cannot be null or empty");
            Contract.Requires(ConfigurationManager.ConnectionStrings[ConnectionStringId] != null, "Connection string must be configured");
            Contract.Ensures(!string.IsNullOrEmpty(Contract.Result<string>()), "A connection string cannot be null");

            return null;
        }
    }

    public string ConnectionStringId
    {
        get
        {
            Contract.Ensures(!string.IsNullOrEmpty(Contract.Result<string>()), "A connection string identifier cannot be null or empty");

            return null;
        }
    }
}

... IWithSqlDbBackend ContractClassAttribute:

[ContractClass(typeof(IWithSqlDbBackendContract))]
public interface IWithSqlDbBackend
{
    ...
}

... DbBackedPersonManager. :

public class DbBackedPersonManager : IPersonManager, IWithSqlDbBackend

, DbBackedPersonManager, AddPerson, / (, web.config app.config...), , , , !

, , - .

0

, ..

public class DbBackedPersonManager : IPersonManager
{
    private readonly string _connectionString;

    public DbBackPersonManager()
    {
        Contract.Requires(ConfigurationManager.ConnectionStrings["SomeConnectionStringId"] != null, "A connection string is required in your application/web configuration file");

        _connectionString = ConfigurationManager.ConnectionStrings["SomeConnectionStringId"];
    }

    [ContractInvariantMethod]
    private void ObjectInvariant()
    {
        Contract.Invariant(_connectionString != null);
    }

    // Interface implementation snipped...
}

DbBackedPersonManager DbBackedPersonManager.

string connectionString ( ConfigurationManager.ConnectionStrings).

+1

Source: https://habr.com/ru/post/1717006/


All Articles