开发者

Subclass needs to implement Interface property as static

开发者 https://www.devze.com 2023-01-12 07:19 出处:网络
My intent is that any API wrapper projects we write in the future around 3rd party or even internal APIs that need a session will need to (should by expected team pattern) implement this interface bec

My intent is that any API wrapper projects we write in the future around 3rd party or even internal APIs that need a session will need to (should by expected team pattern) implement this interface because it will enforce commonality in terms of those API Wrapper projects because I know that any session classes will always have GetCurrentSession, RenewSession, etc. in them...so we have a consistent pattern in terms of common members to be implemented for concrete session classes.

So here's my interface:

/// <summary>
/// Represents an API end user based session
/// </summary>
public interface IAPISession
{
    #region Properties

    int SessionID { get; }

    /// <summary>
    /// Gets the user ID.
    /// Note: type string since userID is not always int in 3rd party APIs 
    /// </summary>
    /// <value>The user ID.</value>
    string UserID { get; }

    bool SessionHasExpired { get; }

    DateTime ExpirationDate { get; }

    void LogOut(); // expires the session & sets SessionHasExpired

    #endregion Properties

    #region Methods

    /// <summary>
    /// Renews the session by returning a brand new session 
    /// if the existing session has expired.
    /// </summary>
    /// <returns></returns>
    IAPISession RenewSession();


    /// <summary>
    /// Gets the current API session
    /// </summary>
    /// <returns></returns&开发者_开发问答gt;
    IAPISession GetCurrentSession();

    #endregion Methods
}

Here is an implementation example:

public class FacebookSession : IAPISession
{
    private static FacebookSession _singletonInstance;

    private FacebookSession() { }

    #region Properties

    private HttpContext CurrentContext { get; set; }

    private HttpCookie CurrentSessionCookie { get; set; }

    #endregion


    #region IAPISession Members

    // Checks for a current session cookie
    public bool SessionHasExpired 
    { 
        get
        {
            return _singletonInstance == null;
        }
    }

    public IAPISession RenewSession()
    {
        throw new NotImplementedException();
    }


    /// <summary>
    /// Gets the current API session singleton instance
    /// </summary>
    /// <returns></returns>
    public static IAPISession GetCurrentSession()
    {
        if (SessionHasExpired)
        {
            return null;
        }

        // TODO: return the singleton instance here...

    }

    public void LogOut()
    {
        throw new NotImplementedException();
    }


    public int SessionID { get; private set; }

    public string UserID { get; private set; }

    public DateTime ExpirationDate { get; private set; }

    #endregion


    public void LogIn(HttpContext currentContext)
    {
        if (SessionHasExpired)
        {
            const string redirectUri = "http://localhost/Photo/FacebookOauth.aspx"; // page they will be redirected to after they auth
            string authUrl = ConfigUtil.GetAppConfigSetting("PayPalBaseUri") + "?client_id=" +
                             ConfigUtil.GetAppConfigSetting("PayPalClientID") +
                             "&redirect_uri=" + redirectUri;

            CurrentContext.Response.Redirect(authUrl); // redirect them to log in
        }
    }
}

and here's my problem. A session is a singleton for the current user thread. To access a singleton, that method GetCurrentSession() which I know all APIs we create will need to implement (will be totally different in HOW they will be implemented based on the API) I need the property to be a static property to get the singleton.

But you can't. Because you can't have static members in an Interface. So...yea I could take out the Interface pattern requirement but I really don't want to.

FYI this is not functional code above, I'm doing my initial coding of all this and trying to design it best.

UPDATE:

On the topic of factories, let me step back to give you more context in what I'm doing here. I needed to get the right custom APIService object (I create a service class for every API wrapper to work with) based on what API wrapper I'm coding for, so I created a GetService factory (or at least attempted to..have not done a lot of factories) like below. And in it you can see that all the methods are static, properties, etc.

Usage example for below would be:

FacebookService service = PhotoServiceFactory.CurrentPhotoUploadServiceFactory;

Thoughts? I'm just trying to do the same for Session but feel I would like to actually expose the related session inside the Specific Service instance that I get back from the factory. So for instance I'd be able to do something like this:

service.CurrentSession which would give me the current facebook singleton session.

The service here is FacebookService type because the factory went out to get it based on the API type I'm working with (API type is an Enum I created that has values like Facebook, Flickr, etc.)

    public class PhotoServiceFactory
    {
        private static PhotoServiceFactory _singletonInstance;

        private PhotoServiceFactory(){}

        #region Properties

        public static PhotoUploadServiceFactory CurrentPhotoUploadServiceFactory
        {
            get
            {
                _singletonInstance = _singletonInstance ?? (_singletonInstance = new PhotoUploadServiceFactory());
                return _singletonInstance;
            } 
        }

        #endregion

        #region Methods

        public static IAPIService GetAPIService(APIType apiType)
        {
            IAPIService apiService = null;

            switch (apiType)
            {
                // return the right service singleton instance
                // based on the API type that we're working with
                case APIType.Facebook:
                    apiService = FacebookAPIService.CurrentFacebookAPIService;
                    break;
                case APIType.Flickr:
                    apiService = null; // service not implemented
                    break;
                case APIType.PhotoBucket:
                    apiService = null; // service not implemented
                    break;
                case APIType.Picasa:
                    apiService = null; // service not implemented
                    break;
                case APIType.Kodak:
                    apiService = null; // service not implemented
                    break;
            }

            return apiService;
        }

        #endregion
    }


Why do you need the property to be static to get the singleton? An instance member can get at static members with no problem - it's the other way round that's tricky.

// This should compile with no problems
public IAPISession GetCurrentSession()
{
    if (SessionHasExpired)
    {
        return null;
    }

    // TODO: return the singleton instance here...
}

If other code needs to get at the session statically, you could have another static member to do that.

Admittedly it's a bit of a design smell for an instance member to only refer to static variables (any instance of FacebookSession will effectively have the same session, if you're on the same thread) but it should work.


You could try using Extension methods for interfaces to provide a common implementation for an interface method. You could declare this extension method in the same namespace/assembly as the interface so that when someone references the interface, the extension method will be there already for them to use. In that implementation, you could use your singleton and it would be a static.

public interface IAPIWrapper
{
    string UserID { get; }
    bool SessionHasExpired { get; }
    DateTime ExpirationDate { get; }
    void LogOut(); // expires the session & sets SessionHasExpired

    IAPISession RenewSession();
    IAPISession GetCurrentSession();
}

public static class IAPIWrapperImpl
{
    private static Session session = new Session(); // Instantiate singleton here

    // This is an extension method for the IAPISession RenewSession method
    // the this keyword before the first parameter makes this an extension method
    public static IAPISession RenewSession(this IAPIWrapper wrapper)
    {
         // implementation details
         // use session here
    }

    // This is an extension method for the IAPISession GetCurrentSession method
    // the this keyword before the first parameter makes this an extension method
    public static IAPISession GetCurrentSession(this IAPIWrapper wrapper)
    {
         // implementation details
         // use session here
    }
}


You can convert the interface to a class, make it abstract, and make all those methods abstract too. Then you can put whatever static fields you want in that abstract base class.


If the method is static, there's really no way to force children to implement it. If you think about how Interfaces are typically used, it makes more sense. The typical use-case is something like:

var myInterfaceInstance = new SomeClassThatImplementsInterface();
myInterfaceInstance.InterfaceMethod();

My suggestion would be to create a Factory to get the different Singleton instances of IAPISession:

public class IAPISessionFactory
{
    public static IAPISession<T> GetInstance() where T : IAPISession
    {
        if(typeof(T) == typeof(ConcreteSession)
            return ConcreteSession.GetInstance();
    }
}


I'm not 100% sure of what you're looking for but you can use statics with an interface. Instead using

public static IAPISession GetCurrentSession()
{
    if (SessionHasExpired)
    {
        return null;
    }

    // TODO: return the singleton instance here...

}

To meet the interface definition you would implement this privately and expose it to the interface

private static IAPISession GetTheCurrentSession()
{
    if (SessionHasExpired)
    {
        return null;
    }

    // TODO: return the singleton instance here...

}

public IAPISession GetCurrentSession()
{
return GetTheCurrentSession();
}
0

精彩评论

暂无评论...
验证码 换一张
取 消