C# Proxy API

I'm working on the C# Client for the WebAPI - this will use HTTP instead of WCF, run on .net standard 2 - so both core and full framework can use it.

Newtonsoft is the only dependency.

Since we are using HTTP, which is async, the new API is also async -- it's quite similar to our Typescript API

  WebApiConfiguration session = new WebApiConfiguration(WebInit.Url);
  session.AuthenticateUsernamePassword("user", "pass");

  ContactAgent agent = new ContactAgent(session);
  var contact = await agent.GetContactEntityAsync(4);
  Assert.AreEqual(4, contact.ContactId);

You can configure timeouts, gzip compression on the configuration object.

You can also set up progress callbacks and error handlers.

What else should the C# proxy support?

RE: C# Proxy API

This sounds very promising!

Will you publish previews on nuget?


Af: Gunnar Stensby 16. sep 2020

RE: C# Proxy API

Previews? Are you implying it will not be perfect from the start?

(Yes - there will be previews)

Af: Christian Mogensen 16. sep 2020

RE: C# Proxy API

This is very nice! 

I've been using the REST api since i wanted to use .net core, so this will open up new ways of doing things :)

Will you add different authentication methods? Like the one that is used for non-interactive authentication with a systemuserToken in 'SuperOffice.SuperID.Client':

public string AuthenticateWithSignedSystemToken(string superIdUrl, string signedSystemToken, string applicationToken, string contextIdentifier, TokenType returnTokenType);


Af: Eivind Johan Fasting 16. sep 2020

RE: C# Proxy API

Nice, that will be useful.

Our latest online application is doing practically the same. It's running on dotnet core, and uses HttpClient inside Agent-classes, and works on models like Contact and ContactEntity, so pretty much the same approach as you're working on. We use System.Text.Json, but Newtonsoft is pretty much identical.

We've ended up using mostly the agents part of the WebApi, not so much the OData section. I find the agents easiest to work with, since it's also almost identical to how we do things in CRMScript.

Like Eivind mentions, supporting SystemUsers is important.

A smooth way of handling refresh tokens would also be nice.

Our variant also supports running against Onsite installations, so hope yours will as well.

A couple of interresting endpoints in addition to the Agents and REST endpoints are the tenant status endpoint (https://community.superoffice.com/en/developer/create-apps/reference/tenant-status/), and the API info endpoint (/api). Including a way to call them would be nice.

Do you have a sneak peak of what the interface for WebApiConfiguration looks like? I'm thinking I'd like to remodel my code to be more in line with what you're thinking, so that its easier to rip out my current implementation and replace it with yours.

Af: Frode Lillerud 16. sep 2020

RE: C# Proxy API

Some whishes from the top of my head:

  1. DI support, the proxy should behave in unit-tests
  2. Use IHttpClientFactory with all the benefits it comes with (recilience, central configuration etc)
  3. SystemUser support (important)
  4. Refresh token handling

Looking forward to try out the previews! ;-)


Af: Gunnar Stensby 17. sep 2020

RE: C# Proxy API

DI support, the proxy should behave in unit-tests

What are you looking for here? A mechanism to replace the http client instance with a mock?

Or something to allow the whole agent to be replaced with a mock?


Use IHttpClientFactory with all the benefits it comes with (recilience, central configuration etc)

That's not in netstandard 2, so that's not happening.

SystemUser support (important)

config.AuthenticateToken( systemToken )

Refresh token handling

Yes - we will try to make this seamless for Online uses.

Af: Christian Mogensen 17. sep 2020

RE: C# Proxy API


Not included .netstandard 2 - so can't use. That's why we use newtonsoft instead. Also it supports discriminants, which we need to support extrafields properly.


We've ended up using mostly the agents part of the WebApi

This client is at the moment just the agents - no REST or ODATA (yet).


supports running against Onsite installations,

Yes - we don't discriminate.


the tenant status endpoint, and the API info endpoint (/api). Including a way to call them would be nice.

Good ideas.

Tenant status requires a cust id + environment name in order to get the right info.


   GetTenantStatusAsync( custid, environment ) --> status object

   GetApiInfoAsync() -> dictionary<string,string>



Af: Christian Mogensen 17. sep 2020

RE: C# Proxy API


Sorry for not elaborating more in my previous post.

With DI support I primarily mean that the proxy should take a HttpClient as a constructor argument.
Then the user of the proxy can use IHttpClientFactory to configure recilience with Polly and other features.

services.AddHttpClient<WebApiConfiguration>(client => 
	client.BaseAddress = new Uri(Configuration["BaseUrl"]);

If someone would like to use IHttpClientFactory in .NET Standard 2.0, it's available in the NuGet package Microsoft.Extensions.Http.

System.Text.Json is also available in .NET Standard 2.0 and later versions. Just install the System.Text.Json NuGet package.
But it lacks some of the features available in Newtonsoft so maybe it's not a viable option in this case.

Af: Gunnar Stensby 18. sep 2020

RE: C# Proxy API

Here's a snippet from an integration test: we are creating a document and setting the document content.


            WebApiConfiguration session = new WebApiConfiguration(WebInit.Url);
            session.AuthenticateUsernamePassword("adm0", "");

            var agent = new DocumentAgent(session);

            var ent = new DocumentEntity();
            ent.Header = "Created by unit test";
            ent.Name = "foox.doc";
            ent.OurRef = "test/1";
            ent.YourRef = "test/99";
            ent.Description = "Unit Tests FTW";
            ent.DocumentTemplate = new DocumentTemplate() { DocumentTemplateId = 2, };    // Notat
            ent.Contact = new Contact() { ContactId = 25 }; // Lena Trevare
            ent.Person = new Person() { PersonId = 63, ContactId = 25, }; // Lars Ludvigsen

            var doc = agent.SaveDocumentEntityAsync(ent).Result;
            long id = doc.DocumentId;

            // api/v1/Document/99/content
            var blank = agent.GetDocumentStreamFromEntityAsync(doc).Result;

            var docString = "TEST DOCUMENT";
            var docBytes = UTF8Encoding.UTF8.GetBytes(docString);
            var doc2 = agent.SetDocumentStreamAsync(doc, docBytes, true).Result;
            Assert.AreEqual(doc.DocumentId, doc2.DocumentId);
Af: Christian Mogensen 18. sep 2020

RE: C# Proxy API

Sounds promising.

  • We would like to be able to create multiple client intances connecting to different SuperOffice intances/customers using different environments and application IDs - within the same process.
  • It would be nice for client objects to be fully configurable programmatically without using .config files.
  • Avoid any implicit magic like relying on thread static stuff - each client instance should be independent and do not share any data. Instead of switching the current context (like it's supposed for the old agents), we would like to be able to just create as many independent clients as needed.


Af: Dmitry Kuskov 11. okt 2020