virtyaluk / InTouch

:busts_in_silhouette: InTouch - is a programming SDK build around vk.com API exposing most of the social platform features including messaging, news feed fetching, communities, and media management.
GNU General Public License v3.0
33 stars 14 forks source link
api c-sharp dotnet intouch netframework netstandard vk vk-api vkontakte windows-uwp wrapper xamarin

InTouch logo

Build status NuGet Join the chat at https://gitter.im/virtyaluk/InTouch

InTouch - is a C# wrapper for vk.com API.

Be sure to check out official VK's :link:Quick start guide before you dive into InTouch.

Compatible with version 5.63 of :link:VK API.

:calendar: Changelog   :ru: Документация на русском.

:dvd: NuGet

PM> Install-Package ModernDev.InTouch

:clipboard: Usage

var clientId = 12345; // API client Id
var clientSecret = "super_secret"; // API client secret
var client = new InTouch(clientId, clientSecret);

// Authorization works only in Windows (and WinPhone) Store Apps
// otherwise you'll need to set received "access_token" manually
// using SetSessionData method.
await client.Authorize();

// Gets a list of a user's friends.
var friends = await client.Friends.Get();

if (friends.IsError == false)
{
    ShowFriendsList(friends.Data.Items.Where(friend => friend.Online));
}

client.Dispose();

or even simpler:

using (var client = new InTouch(12345, "super_secret"))
{
    await client.Authorize();

    var friends = await client.Friends.Get();
    // ...
}

:mortar_board: API Reference

After you :link:register an app, you'll get a unique ClientID and ClientSecret. These needed to perform user :link:authorization and to call several methods from :link:Auth category. You may avoid using ClientID and ClientSecret if you do not intend to use authorization or methods from Auth category.

You may use one of following constructors to produce a new instance of InTouch class.

new InTouch(int clientId, string clientSecret, bool throwExceptionOnResponseError = false,
    bool includeRawResponse = false);
new InTouch(bool throwExceptionOnResponseError = false, bool includeRawResponse = false)
Values:

You can also set client data after creating an instance of class just by using SetApplicationSettings class method.

void SetApplicationSettings(int clientId, string clientSecret);

:information_source: Note: The current API session will be reset each time you change client data using SetApplicationSettings method.

Authorization

In order to call most API methods, your application require user authorization.

Authorization may be performed using the Authorize method, which is available for Windows Store Apps. Otherwise, you need to implement your own authorization logic based on steps described in the :link:official documentation and then set received data on client using the SetSessionData method.

In case of Windows Store Apps, you need to await the Authorize method which starts the authentication operation and shows auth dialog to the user. In case of success, auth data will be set to the client automatically, no need to take additional actions.

async Task Authorize(AuthorizationSettings authSettings = null, bool silentMode = false);
Values:

Where authSettings is an instance of class AuthorizationSettings which describes the next data structure:

class AuthorizationSettings {
    // Authorization window appearance.
    AuthorizationDisplayTypes Display = AuthorizationDisplayTypes.Mobile,

    // Requested application access permissions.
    AccessPermissions Scope = AccessPermissions.None,

    // Whether the authorization dialog must revoke previously accessed application permissions.
    bool Revoke,

    // URL where access_token will be passed to.
    Uri RedirectUri = new Uri("https://oauth.vk.com/blank.html"),

    // Whether the app supports single sign-on (SSO).
    bool SSOEnabled,
}

:information_source: Note. VK API doesn't yet support SSO. There is a feature request submitted by me though. So auth dialog will be displayed each time the Authorize method would called.

Let's say we need to get access to user's friends and private messages through authorization on devices with large screen. In this case, we'll pass the next object as the first argument in Authorize method:

await client.Authorize(new AuthorizationSettings {
    Display = AuthorizationDisplayTypes.Page,
    Scope = AccessPermissions.Friends | AccessPermissions.Messages
});

In the case of custom authorization, after the authorization completes you'll need to pass auth data to the SetSessionData method which takes 3 arguments.

void SetSessionData(string accessToken, int userId, int sessionDuration = 20*60*60);
Values:

After successful authorization, you can make API requests. There're a couple of methods not requiring authorization, though.

Community Token

A community token allows working with API on behalf of a group, event or public page. It can be used to answer the community messages.

InTouch offers GetClientCredentialsFlow method to get community token:

async Task<ClientCredentialsFlowStatus> GetClientCredentialsFlow(int? clientId = null, string clientSecret = null);

In case of omitting clientId and clientSecret arguments, InTouch would try to use ClientId and ClientSecret properties on main class instance.

In case you already have community token, you can set it on main class instance manually using SetServiceToken method:

void SetServiceToken(string serviceToken)

and later access using ServiceToken property.

API Requests

All the methods are grouped by corresponding categories as they were presented in the :link:official documentation. So, for example, if you want to return a list of posts on a user's wall using :link:wall.get method, you need to call Get method of Wall object on the main instance of InTouch class. Like so:

await client.Wall.Get(new WallGetParams {
    Count = 10,
    Extended = true
});

:information_source: Oh, by the way, InTouch brings all the advantages of :link:async programming. Which means there are only a couple of non-async methods and all the rest are async. So you need to await them.

Parameters transmissiton in API

Most of the methods have its own parameters that are described in the docs. If a method (like :link:this one) takes more than 6 arguments then these arguments will be combined into the one object. Here's what that means.

The wall.get method takes next parameters: owner_id, domain, offset, count, filter, extended, fields.

But InTouch version of this method takes only one argument which is an instance of WallGetParams class and has the next structure:

class WallGetParams {
    // User or community id.
    int OwnerId,

    // User or community screen name.
    string Domain,

    // True – returns only page owner's posts.
    bool OwnersOnly = false,

    // Count of posts to return.
    int Count = 20,

    // Results offset.
    int Offset = 0,

    // Show extended post info.
    bool Extended = false,

    // The list of additional fields for the profiles and groups that need to be returned.
    List<object> Fields = null,

    // Filter to apply.
    PostFilterTypes Filter = PostFilterTypes.All
}

And the :link:wall.getById method have short arguments list and thus has the next signature:

async Task<Response<ItemsList<Post>>> GetById(List<string> posts, bool extended = false,
    int copyHistoryDepth = 2, List<object> fields = null);

:information_source: Keep in mind, InTouch would throw an exception if not all required parameters filled with data. Optional parameters may be omitted.

Each method has its own set of supported parameters but there are some common ones:

client.DataLanguage = Langs.English;
client.AlowHttpsLinks = true;
client.TestMode = false;

Response object

Calling to the API will always result in Response object which describes the next data structure:

class Response<T> {
    // Response error (if any).
    ResponseError Error,

    // Response data (if any).
    T Data,

    // Whether the request response is error.
    bool IsError => Error != null,

    // Raw JSON response.
    string Raw
}

So, for example, retrieving friends list using :link:friends.get method will result in Response<ItemsList<User>>, where Data property would be of type ItemsList<User>.

If API request resulted in error then the Error property would contain the error object describing the error code and the error message:

class ResponseError: EventArgs {
    // Error code.
    int Code,

    // Error text.
    string Message,

    // Captcha identifier.
    string CaptchaSId,

    // A link to an image that will be shown to a user.
    string CaptchaImg,

    // Request parameters.
    Dictionary<string, string> RequestParams
}

There are few options using which you can control how InTouch handles response errors.

// If set to true, then an exception will be thrown in case of response error,
// instead of passing an error object to the Response object.
client.ThrowExceptionOnResponseError = true;

// If set to true, then Response.Raw will be filled with raw JSON response string.
client.IncludeRawResponse  = true;

try {
    var audios = await client.Audios.Get(count: 10);

    OwnWayToAnalyzeRawResp(audios.Raw);
    FillAudiosList(audios.Data);
} catch (InTouchResponseErrorException ex) {
    MessageBox.Show(ex.ResponseError.Message);
}

Handling Authorization\Captcha errors.

Whenever API call gets authorization failed error or captcha needed error, AuthorizationFailed or CaptchaNeeded event will be fired accordingly. So there's no need to check response error on these two, you can simply subscribe to custom events and use custom logic whenever it's needed.

client.AuthorizationFailed += OnAuthorizationFailed;

client.CaptchaNeeded += (s, error) => ShowCaptchaBox(error.CaptchaImg, error.CaptchaSId);

Moreover, there is an utility method that helps you to resend previously failed request with captcha code:

async Task<Response<T>> SendCaptcha<T>(string captchaKey, ResponseError lastResponseError);

There is also an utility method called TrySendRequestAgain which is designed to resend previously failed request:

async Task<Response<T>> TrySendRequestAgain<T>();

:information_source: Note: Keep in mind that custom events will occur only and only when the ThrowExceptionOnResponseError is set to false, which is the default value.

Limits and recommendations

There can be maximum 3 requests to API methods per second from a client.

Maximum amount of server requests depends on the app's users amount. If an app has less than 10 000 users, 5 requests per second, up to 100 000 – 8 requests, up to 1 000 000 – 20 requests, 1 000 000+ – 35 requests.

If one of this limits is exceeded, the server will return following error: 'Too many requests per second'.

If your app's logic implies many requests in a row, check the execute method.

Except the frequency limits there are quantitative limits on calling the methods of the > same type. By obvious reasons we don't provide the exact limits info.

On excess of a quantitative limit access to a particular method will require captcha (see captcha_error). After that it may be temporarily limited (in this case the server doesn't answer on particular method's requests but easily processes any other requests).

Other

Custom API request

You may want to get full control on what you send through the request. InTouch exposes Request method to send VK API requests. All the InTouch API methods are build on top of the one. The signature is next:

async Task<Response<T>> Request<T>(string methodName, Dictionary<string, string> methodParams = null,
    bool isOpenMethod = false, string path = null);
Values:

The next example shows how to get a list of user's friends using the Request method:

var friends = await client.Request<ItemsList<User>>("friends.get", new Dictionary<string, string> {
    {"user_id", "16815310"},
    {"count", "10"},
    {"order", "name"}
});

Uploading Files

InTouch supports :link:uploading files through API.

Next example demonstrates how to upload document to user's page.

byte[] docFile = GetMyFile("cats.gif");

var uploadedDocs = await client.Docs.UploadDoc(docFile, "cats.gif", title: "my funny cat");

ShowUploadedDoc(uploadedDocs.Data[0]);

or how to update user's profile photo:

byte[] newPhoto = GetMyFile("photo.jpg");

await client.Photos.UploadOwnerPhoto(newPhoto, "profile.jpg");

:green_book: Platform Support

InTouch is compiled for .NET 4.5, Portable Class Library (Profile 111) and .NET Standard 1.1:

:green_book: License

Licensed under the GPLv3 license.

Copyright (c) 2017 Bohdan Shtepan


modern-dev.com  ·  GitHub @virtyaluk  ·  Twitter @virtyaluk