Configuration

Clients

A FilesClient connects to one Files.com site with one set of credentials. FilesClient.Create(config) makes an independent client. Its properties, such as client.Users or client.RemoteFiles, run operations with that client, and the objects and lists they return keep using it. Make one client for each site or user you work with; clients can be used at the same time.

Create copies the configuration, so later changes to config do not affect the client. Reuse the client because each client has its own connection pool.

new FilesClient(config) makes the default client, which static methods such as User.Find(id) use. Making another replaces the default for later static calls, but an object keeps the client it came from. A client made this way reads config as each operation starts, so changes you make apply to operations started afterward; its connections keep the ConnectTimeout it was made with.

Example Request

using FilesCom;
using FilesCom.Models;

var config = new FilesConfiguration();
config.BaseUrl = "https://MY-SUBDOMAIN.files.com";
config.ApiKey = "YOUR_API_KEY";

await using FilesClient client = FilesClient.Create(config);

try
{
    User user = await client.Users.FindAsync(id);
    await user.UpdateAsync(new Dictionary<string, object> { { "name", "New Name" } });
}
catch (FilesCom.NotAuthenticatedException e)
{
    Console.WriteLine($"Authentication Error Occurred ({e.GetType().Name}): " + e.Message);
}
catch (FilesCom.SdkException e)
{
    Console.WriteLine($"Unknown Error Occurred ({e.GetType().Name}): " + e.Message);
}

Closing a Client

Dispose a client when you no longer need it; await using or using does it for you. From then on, the client, and the objects, lists and transfers it returned, throw ObjectDisposedException for any new operation. Disposing cancels the operations the client is running, and closes its connections once the SDK has finished with what they use: their requests, responses and temporary files, and a stream an operation owns, such as the one UploadFileAsync(destinationPath, stream, ...) disposes. DisposeAsync completes when that is done and the connections are closed; Dispose does the same without waiting. A list or enumerator that is not loading a page does not delay closing.

DisposeAsync does not wait for the operations' own tasks: await each one for its outcome. A running operation usually ends with OperationCanceledException, as when its token is cancelled, but one whose response had already arrived can still succeed, and an upload whose final request had been sent may have completed the file. Its task can complete after DisposeAsync does, for example while it turns the response it received into its result.

An operation reading or writing a stream you gave it waits for that stream's current read or write, which the SDK never forces closed, so a stream that ignores cancellation also delays DisposeAsync. Do not await DisposeAsync inside a progress handler of the client's own transfer, which waits for the handler; Dispose returns at once there.

Disposing the default client leaves it as the default, so later static calls throw ObjectDisposedException until you make a new one. Making a new default client does not dispose the previous one.

HTTP Transport

To send a client's requests through your own proxy, TLS settings, certificate checks or instrumentation, give it an HttpTransport. The SDK still decides everything above the handlers, for API requests and file transfers alike: the endpoint and credentials of each request, which redirects to follow and which headers go with them, retries, timeouts and cancellation.

  • HttpTransport.FromHandlerFactory(() => new HttpClientHandler { ... }) gives the client handlers to own. It calls your function whenever it needs a new handler, including when it replaces its handlers from time to time to pick up DNS changes, and disposes each handler when it is done with it, and every remaining one when the client is disposed. Return a new handler each time.
  • HttpTransport.FromSharedHandler(handler) sends through a handler you own and share. Clients never change or dispose the shared handler. Dispose it after disposing every client that uses it.

The SDK follows redirects itself, so that credentials never go to another origin. It turns off redirects on the handlers your factory returns, and refuses a shared HttpClientHandler or SocketsHttpHandler whose AllowAutoRedirect is true. A handler of another kind must not follow redirects or retry requests itself: the SDK sends a request that can change something, such as a DELETE or the one that completes an upload, once per attempt, and again only where Files.com redirects it, and it cannot know that a handler sent one again.

Example Request

using System.Net;
using System.Net.Http;
using FilesCom;

var transport = HttpTransport.FromHandlerFactory(() => new HttpClientHandler
{
    Proxy = new WebProxy("http://proxy.example.com:8080"),
    UseProxy = true,
});

await using FilesClient client = FilesClient.Create(config, transport);

Configuration Options

Base URL

Set this to the full https:// URL of your Files.com subdomain (e.g. https://MY-SUBDOMAIN.files.com). This is not required in most cases, but one benefit of setting it is that it ensures that authentication failures will be logged to your site's API logs. Without setting this, we won't know which site to associate the authentication failure with, and it won't be logged to your site's API logs. This is always required if your site is configured to disable global acceleration. This can also be set to use a mock server in development or CI.

Example setting

using FilesCom;

var config = new FilesConfiguration();
config.BaseUrl = "https://MY-SUBDOMAIN.files.com";

Connect Timeout

How long, in seconds, to wait to connect to a server. The default value is 30.

On .NET 8 and later the client applies it to the handlers it makes itself, and to a SocketsHttpHandler from an HttpTransport factory whose own ConnectTimeout is not set. A connection that it ends was never made, so nothing was sent, and the request is retried, within Maximum Network Retries, even when it can change something.

It is not applied to any other handler: a shared handler, whose settings the SDK never changes, or a factory's handler of another type or whose own ConnectTimeout is already set. Such a handler connects as it is configured, with its own connection settings in effect. On .NET Framework, or any other runtime that uses the SDK's .NET Standard 2.0 build, the handlers the client makes itself have no separate connect timeout.

Whatever the handler, connecting also counts toward the wait that follows it: the Read Timeout for an API request or a download, and the Write Timeout for an upload part or a request with file attachments. Whichever limit runs out first ends the attempt. When that wait runs out before a connection is made, as it does where no shorter connect timeout applies, the request fails with NetworkTimeoutException for that timeout, and a request that can change something is not sent again after it, since the SDK cannot tell that nothing was sent.

None of the timeouts limits how long a whole request, transfer or connection takes: each limits one wait on the network.

Example setting

using FilesCom;

var config = new FilesConfiguration();
config.ConnectTimeout = 60;

Read Timeout

How long, in seconds, a request may wait for its response once it has been sent, and then between the parts of the response as they arrive. The default value is 80.

It limits a stalled connection, not how long a response takes: a download that keeps receiving data continues however long it lasts. A request that times out fails with NetworkTimeoutException, after the retries a connection failure gets. An error response whose body stops arriving fails with its HTTP status, as an InvalidResponseException, and is retried as that status is.

Example setting

using FilesCom;

var config = new FilesConfiguration();
config.ReadTimeout = 90;

Write Timeout

How long, in seconds, an upload part may go without sending any data: to connect and start, and then each time it sends more. The default value is 80.

It limits a stalled connection, not how long an upload takes, and time spent reading your file or stream is not counted. A part that times out is retried like one whose connection failed.

Example setting

using FilesCom;

var config = new FilesConfiguration();
config.WriteTimeout = 120;

Maximum Network Retries

MaxNetworkRetries limits the SDK's retries after temporary failures. The default is 3; 0 disables SDK retries. Eligible failures are connection failures, timeouts, HTTP 408, HTTP 429, and 5xx other than 501. Each SDK retry is logged with its reason, number and wait.

RequestWhen the SDK retries
Reads, such as GETAfter an eligible temporary failure.
Requests that can change data, such as creating a userOnly when the request certainly did not take effect: nothing was sent, or a trusted regional-relocation response allows it to move.
Transfer requests explicitly safe to repeatLike reads: for example, obtaining an upload part's address or creating a folder that may already exist.
Upload completionNever automatically retried. Check the remote file if completion is uncertain.

For a potentially mutating request, a lost answer, timeout or error response can occur after the change took effect. The SDK does not replay it, even with retries left. Its exception has RequestMayHaveBeenProcessed set: check the outcome before sending the request again. No error status or body, including a rate-limit response, proves that the change did not begin.

A false flag alone does not guarantee safe replay. For example, an InvalidResponseException with httpStatus = 0 can mean a successful response was unusable by CreateAsync: the change took effect, and no error response is attached.

Transfer parts have their own retry rules. New file downloads can retry into staging; downloads into your stream, and earlier whole-file download methods, cannot retry after writing bytes. See Transfers.

HTTP Handler and Redirect Caveats

This setting counts SDK retries, not every network send. Within an attempt, .NET's handler can resend a read after a connection closes without an answer; even 0 does not guarantee a single send. The SDK gives mutating requests content, including an empty body for a DELETE, to prevent the handler's automatic replay of bodyless requests.

SDK-managed redirects are still followed within an attempt: 307 and 308 resend the method and body to the new address. This is routing, and neither redirects nor retry settings guarantee exactly-once processing. A custom HttpTransport handler must not perform its own retries or follow redirects, since the SDK could not track them or reliably report whether a change may have taken effect.

Certificate failures, refused redirects and failures of caller-owned streams are not retried.

Example setting

using FilesCom;

var config = new FilesConfiguration();
config.MaxNetworkRetries = 5;

Initial Network Retry Delay

The wait, in seconds, before the first retry of a Files.com API request. Each later retry waits twice as long as the one before, up to the Maximum Retry Delay. The default value is 0.1, so the default retries wait 0.1, 0.2 and 0.4 seconds.

File-transfer retry behavior is described in Transfers.

Example setting

using FilesCom;

var config = new FilesConfiguration();
config.InitialNetworkRequestDelay = 1;

Maximum Retry Delay

The longest wait, in seconds, before a retry of a Files.com API request. The default value is 2.

Example setting

using FilesCom;

var config = new FilesConfiguration();
config.MaxNetworkRetryDelay = 5;

Regional Relocation

When a site is served from another region's address, Files.com answers a request sent elsewhere with LockoutRegionMismatchException and the site's address, its domain or its URL. With the default, RegionRelocationPolicy.Automatic, the client then sends the request again to that address, with the same credentials and body, when:

  • the answer came from the address the request was sent to, over HTTPS whose certificate the client's handler checked as strictly as .NET does by default, against the system's trusted roots or a custom trust store, at every request since the handler's first (as the client saw its settings when each request started and when its answer arrived), and not after a redirect to another origin. The handler is the client's own or one from HttpTransport.FromHandlerFactory: a client cannot see how a shared handler checked the servers it connected to before, or for other code;
  • the address is an HTTPS origin on port 443 with a public DNS name, such as the site's own domain, and not the one already used;
  • the operation has not moved already and has a retry left: moving is one of its Maximum Network Retries, so with 0 the error is thrown instead.

The operation sends its remaining requests there, and so do the objects and lists it returns, for their own operations and next pages. The client's configuration is unchanged, and other operations start at the Base URL.

RegionRelocationPolicy.Disabled never moves: the error is thrown for your application to act on, such as by changing its Base URL. RegionRelocationPolicy.OnlyBetween(from, to), with more pairs added by OrBetween, moves only from the first origin of a pair you list to its second; a pair moves one way, so list the way back as another pair. The origins may use another port, a local name or plain HTTP, as a development site may need, or answer through a handler whose certificate checks the client cannot see or that relaxes them, such as a shared handler, a RemoteCertificateValidationCallback of your own, or a CertificateChainPolicy with AllowUnknownCertificateAuthority, even one tightened after the handler's first request.

When the operation does not move, the exception's RequestedOrigin is the address Files.com named, and Refusal says why, such as RegionRelocationRefusal.Disabled or RetriesExhausted. For UntrustedIssuer, the message says which condition the answer failed, and names the pair that would allow the move only when a pair can.

Example setting

using FilesCom;

var config = new FilesConfiguration();
config.RegionRelocation = RegionRelocationPolicy.Disabled;

// Or only between exact origins:
config.RegionRelocation = RegionRelocationPolicy.OnlyBetween(
    "https://files.example.com", "https://files.example.eu");

Logging

Set LoggerFactory to your application's ILoggerFactory to receive SDK messages under categories named for SDK classes in the FilesCom namespace. Each client uses its own factory, so clients in one process can use different log destinations without global configuration. A client without a factory uses log4net, as described in Logs.

MinimumLogLevel filters out a client's messages below that level, even if its logger enables them. Setting LogLevel.Warning excludes that client's Information messages. Each client retains the logger factory and minimum level set when it was created.

Example setting

using FilesCom;
using Microsoft.Extensions.Logging;

var config = new FilesConfiguration();
config.LoggerFactory = loggerFactory; // for example, from the host's services
config.MinimumLogLevel = LogLevel.Warning;

Product Identity

ProductName and ProductVersion name the application or module using the SDK. A client sends them as the first product of its User-Agent header, before the SDK's own, Files.com DOTNET SDK and its version, which it always sends. Each must be an HTTP token, without spaces; a client with any other value is refused as it is made, with ArgumentException. A client keeps the values it was made with.

Example setting

using FilesCom;

var config = new FilesConfiguration();
config.ProductName = "MyBackupTool";
config.ProductVersion = "1.4.0";
// User-Agent: MyBackupTool/1.4.0 Files.com DOTNET SDK v2.0.0