Get started with BitTitan SOAP APIs
MigrationWiz implements a simple, secure SOAP-based API allowing callers to perform operations such as:
Using the MigrationWiz SOAP API, you enable data migration from and to a multitude of systems, and enable on-demand migrations without the need for any user interaction or for a dedicated migration infrastructure.
Need help? Contact us to request code snippets, sample code, or for general technical support.
To use the MigrationWiz SOAP API, the following are required:
All accounts must be API-enabled before they can access the MigrationWiz SOAP API. Contact us to request access (or check if your account is API-enabled).
The MigrationWiz SOAP API implements a single web service called WebService, exposing a single method called Execute. Its implementation is available at:
https://www.migrationwiz.com/API/2.0/WebService.asmx?wsdl
https://www.migrationwiz.com/API/2.0/WebService.asmx
To generate a client access proxy using Visual Studio 2013, follow these simple steps (similar steps can be used with other versions of Visual Studio):
References
.Add Service Reference
.Advanced
.Add Web Reference
.Add Reference
.After completing these steps, add a "using" statement for the selected namespace, and copy/paste the following code:
WebService webService = new WebService
{
Url = "https://www.migrationwiz.com/API/2.0/WebService.asmx"
};
The MigrationWiz SOAP API uses a simple request/response model. For each request message submitted to the web service’s Execute method, a response message is returned to the caller.
The following types of requests are available:
AuthenticateRequest | Provides authentication tickets. |
---|---|
RetrieveRequest | Finds entities such as mailboxes, mailbox connectors, etc. |
CreateRequest | Creates entities such as mailboxes, mailbox connectors, etc. |
UpdateRequest | Modifies entities such as mailboxes, mailbox connectors, etc. |
DeleteRequest | Deletes entities such as mailboxes, mailbox connectors, etc. |
ScalarRetrieveRequest | Requests a calculated value such as a sun, max, min, or average value over entities. |
The following response types are available:
AuthenticateResponse | Returns authentication tickets. |
---|---|
RetrieveResponse | Returns found entities such as mailboxes, mailbox connectors, etc. |
CreateResponse | Confirms creation of entities such as mailboxes, mailbox connectors, etc. |
UpdateResponse | Confirms modification of entities such as mailboxes, mailbox connectors, etc. |
DeleteResponse | Confirms deletion of entities such as mailboxes, mailbox connectors, etc. |
FailureResponse | Returns information about failure to process a request. |
ScalarRetrieveResponse | Returns a calculated value such as a sum, max, min, or average value over entities. |
Here is an example demonstrating the request/response mechanism:
// Prepare authenticate request
AuthenticateRequest authenticateRequest = new AuthenticateRequest
{
EmailAddress = "user@domain.com",
Password = "password"
};
// Perform authenticate request
AuthenticateResponse authenticateResponse = (AuthenticateResponse)webService.Execute(authenticateRequest);
Callers authenticate by presenting credentials using AuthenticationRequest messages. Obtained authentication tickets must then be attached to subsequent requests for authentication purposes.
Here is an example showing a simple authentication and execution routine:
// Prepare authenticate request
AuthenticateRequest authenticateRequest = new AuthenticateRequest
{
EmailAddress = "user@domain.com",
Password = "password"
};
// Perform authenticate request
AuthenticateResponse authenticateResponse = (AuthenticateResponse)webService.Execute(authenticateRequest);
Ticket ticket = authenticateResponse.Ticket;
Console.WriteLine(ticket.ExpirationDate);
// Prepare create request
CreateRequest createRequest = new CreateRequest
{
Ticket = ticket,
Entities = new Entity[]
{
//...
}
};
// Perform create request
CreateResponse createResponse = (CreateResponse)webService.Execute(createRequest);
If the AuthenticateRequest fails for any reason, the caller receives a FailureResponse message with detailed error information. Tickets usually expire, so callers should renew tickets as needed. In any case, callers should not retrieve a new ticket each time a request is sent (callers should cache tickets).
While tickets normally only represent the account whose identity matches the specified email address, privileged accounts can also impersonate other accounts by setting the ImpersonateUserId property. However, this functionality is for internal use only and currently unavailable to external callers. We recommend not setting this property.
The MigrationWiz SOAP API allows callers to configure, initiate and monitor migrations using different types of entities.
The following entity types are available:
Entity | Description |
---|---|
MailboxConnector | Represents configuration information about a source and destination messaging system. |
Mailbox | Represents configuration information about a source and destination mailbox. |
MailboxMigration | Represents an active, completed, or failed mailbox migration. |
MailboxStats | Represents statistics about an active, completed, or failed mailbox migration. |
To perform a migration, follow these steps:
To monitor a migration, follow these steps:
Creating a MailboxMigration entity also means scheduling a migration. For non-trial migrations, MigrationWiz credits will be debited from your account. For testing purposes, simply create MailboxMigration entities whose Type property is set to Trial (no credits will be debited for trial migrations). Because only one trial migration is allowed per email address, you may need to log in to our web site and reset the email address’s trial migration state.
The following actions are allowed:
Entity | Retrieve | Create | Update | Delete |
---|---|---|---|---|
MailboxConnector | Yes | Yes | Yes | Yes |
Mailbox | Yes | Yes | Yes | Yes |
MailboxMigration | Yes | Yes | Yes (only to stop) | No |
MailboxStats | Yes | No | No | No |
Note the following:
Callers must retrieve entities using RetrieveRequest messages. Callers must specify the type of entity to retrieve. Callers can specify optional filtering and sorting criteria. For example, a caller may decide to retrieve all mailbox connectors created in the last 10 days, sorting them by creation date in descending order. However, more complex multi-level filtering and ordering criteria are also possible.
Here is an example showing a simple entity retrieve routine:
// Prepare retrieve request
RetrieveRequest retrieveRequest = new RetrieveRequest
{
Ticket = ticket,
EntityName = typeof(MailboxConnector).Name,
Offset = 0,
Count = int.MaxValue,
SearchCondition = new SearchCondition
{
IsOrCondition = false,
SearchFilters = new SearchFilter[]
{
new SearchFilter
{
PropertyName = "CreateDate",
ComparisonOperator = ComparisonOperator.Greater,
Value = DateTime.Now.AddDays(-10)
}
}
},
SearchOrders = new SearchOrder[]
{
new SearchOrder
{
PropertyName = "CreateDate",
IsAscending = false
}
}
};
// Perform retrieve request
RetrieveResponse retrieveResponse = (RetrieveResponse)webService.Execute(retrieveRequest);
// Print retrieved entities
foreach (MailboxConnector mailboxConnector in retrieveResponse.Entities)
{
Console.WriteLine(mailboxConnector.Name);
Console.WriteLine(mailboxConnector.CreateDate);
}
If the RetrieveRequest fails for any reason, the caller receives a FailureResponse message with detailed error information. The MigrationWiz SOAP API limits the number of entities returned by a single request. By default, the limit is 100 entities. As a best practice, callers should implement paging to retrieve larger data sets. Simply specify the offset to match the count of entities retrieved so far.
The MigrationWiz SOAP API is designed to protect configuration data stored on behalf of its customers. Only records associated with the calling account can be retrieved. In addition, the API will reject any request whose search or ordering criteria references a property storing passwords. Finally, for all retrieved entities, properties storing passwords are set to a placeholder value (example: "********").
The MigrationWiz SOAP API is designed to support complex multi-level filtering criteria. Each SearchCondition object can specify a list of SearchFilter objects, all joined by a single AND or OR clause, but also (optionally) a list of child SearchCondition objects. This provision allows callers to construct complex and/or condition trees. However, in most cases, this is not necessary.
Callers must create entities using CreateRequest messages. Callers must specify a list of entities to create. If not specified, IDs are automatically assigned by the system.
Here is an example showing a simple entity create routine:
// Prepare create request
CreateRequest createRequest = new CreateRequest
{
Ticket = ticket,
Entities = new Entity[]
{
new MailboxConnector
{
Id = Guid.NewGuid()
// set additional properties
}
}
};
// Perform create request
CreateResponse createResponse = (CreateResponse)webService.Execute(createRequest);
// Print created entities
foreach (ProcessingError processingError in createResponse.ProcessingErrors)
{
Console.WriteLine(processingError.ErrorCode);
Console.WriteLine(processingError.Entity);
}
If the CreateRequest fails entirely, the caller receives a FailureResponse message with detailed error information. If the CreateRequest fails partially (example: some entities could not be created), the caller receives ProcessingError objects within a CreateResponse message. The MigrationWiz SOAP API limits the number of entities which can be created by a single request. By default, the limit is 10 entities. As a best practice, callers should use multiple requests to create a large number of entities.
Callers must update entities using UpdateRequest messages. Callers must specify a list of entities to update. Entity IDs assigned during creation cannot be changed.
Here is an example showing a simple entity update routine:
// Prepare update request
UpdateRequest updateRequest = new UpdateRequest
{
Ticket = ticket,
Entities = new Entity[] { mailboxConnector }
};
// Perform update request
UpdateResponse updateResponse = (UpdateResponse)webService.Execute(updateRequest);
// Print updated entities
foreach (ProcessingError processingError in updateResponse.ProcessingErrors)
{
Console.WriteLine(processingError.ErrorCode);
Console.WriteLine(processingError.Entity);
}
If the UpdateRequest fails entirely, the caller receives a FailureResponse message with detailed error information. If the UpdateRequest fails partially (example: some entities could not be updated), the caller receives ProcessingError objects within an UpdateResponse message. The MigrationWiz SOAP API limits the number of entities which can be updated by a single request. By default, the limit is 10 entities. As a best practice, callers should use multiple requests to update a large number of entities.
Updates have no effect on migrations which are already in progress. For example, if you change the properties of a mailbox, but a migration is already in progress for that mailbox, the changes you made will have no effect. We recommend stopping any active migration before making changes to associated entities.
Callers must create entities using DeleteRequest messages. Callers must specify a list of entity targets to delete. Each entity target specifies the entity type and ID to delete.
Here is an example showing a simple entity delete routine:
// Prepare delete request
DeleteRequest deleteRequest = new DeleteRequest
{
Ticket = ticket,
EntityTargets = new EntityTarget[]
{
new EntityTarget
{
Id = mailboxConnector.Id,
EntityName = typeof(MailboxConnector).Name
}
}
};
// Perform delete request
DeleteResponse deleteResponse = (DeleteResponse)webService.Execute(deleteRequest);
// Print deleted entities
foreach (ProcessingError processingError in deleteResponse.ProcessingErrors)
{
Console.WriteLine(processingError.ErrorCode);
Console.WriteLine(processingError.EntityTarget.EntityName);
Console.WriteLine(processingError.EntityTarget.Id);
}
If the DeleteRequest fails entirely, the caller receives a FailureResponse message with detailed error information. If the DeleteRequest fails partially (example: some entities could not be deleted), the caller receives ProcessingError objects within a DeleteResponse message. The MigrationWiz SOAP API limits the number of entities which can be deleted by a single request. By default, the limit is 10 entities. As a best practice, callers should use multiple requests to delete a large number of entities.
Deletes may fail if associated entities are in actively in use. For example, if you delete a mailbox, but a migration is already in progress for that mailbox, the delete request may fail. We recommend stopping any active migration before deleting associated entities.
The MigrationWiz SOAP API reports errors using ProcessingError objects. Each ProcessingError object contains detailed information about processing failures. Depending on the failure, only some of the properties listed below may be set.
Property | Description |
---|---|
Entity | Entity for which processing failed. |
EntityTarget | Target for which processing failed. |
ErrorCode | Detailed error code. |
Property | Name of property for which processing failed. |
Value | Value of a property for which processing failed. |
Message | Additional information about the failure. |
If a SOAP request failed entirely (for example because you forgot to include a ticket), the web service returns a FailureResponse message containing a single ProcessingError object. Below is an example of global failure handling:
// Prepare create request
CreateRequest createRequest = new CreateRequest
{
Ticket = null, // ticket missing
Entities = new Entity[]
{
// ...
}
};
// Perform create request
FailureResponse failureResponse = (FailureResponse)webService.Execute(createRequest);
// Print error
Console.WriteLine(failureResponse.ProcessingError.ErrorCode);
If a SOAP request failed in a partial manner (for example: because only some of the entities could not be created), the web service returns a normal response (example: CreateResponse) containing ProcessingError objects indicating which entities it failed to process. Here is an example of partial failure handling:
// Prepare create request
CreateRequest createRequest = new CreateRequest
{
Ticket = ticket,
Entities = new Entity[] { null } // invalid entity
};
// Perform create request
CreateResponse createResponse = (CreateResponse)webService.Execute(createRequest);
// Print error
foreach (ProcessingError processingError in createResponse.ProcessingErrors)
{
Console.WriteLine(processingError.ErrorCode);
Console.WriteLine(processingError.Entity);
}
The MigrationWiz SOAP API is designed to produce useful, detailed, actionable error information. For example, if a property was unexpectedly set to a negative value, a ProcessingError specifying the name of the property, the minimum expected value, and a specific error code (e.g., PropertyMustBeMore) will be returned.
MigrationWiz recently introduced a new version of its SOAP API that supports all new systems introduced in the past months (such as Google Drive, OneDrive, PST, Open Exchange ...).
This API v2 is mostly compatible with the previous API (~ 90%) but some key services have changed. This document lists all changes introduced by the new API.
Note that the API v1 will stay active and backward compatible until June, 1st 2015. After this date, all API calls should be made to the v2 endpoint and using a proxy generated from the v2 WSDL.
API Endpoint: https://www.migrationwiz.com/API/2.0/WebService.asmx
API WSDL: https://www.migrationwiz.com/API/2.0/WebService.asmx?WSDL
// Create the mailbox connector
MailboxConnector mailboxConnector = new MailboxConnector
{
// Set administrative usernames and passwords (optional)
ExportAdministrativeUserName = "admin_username", // set source admin username (consumer key)
ExportAdministrativePassword = "admin_password", // set source admin password (consumer secret)
ImportAdministrativeUsername = "admin_username", // set destination admin username
ImportAdministrativePassword = "admin_password", // set destination admin password
// Set basic properties
Id = Guid.NewGuid(), // auto-generated if unspecified
Name = "My Example Connector", // connector display name
UserId = ticket.UserId, // own user ID
ExportType = MailboxConnectorTypes.Gmail, // system to migrate from (type)
ExportSettings = new MailboxConnectorSettingsZimbra // system to migrate from (configuration)
{
Url = "https://my.zimbra.server.com",
ContactHandling = ContactHandling.SkipSuggestedContacts
},
ImportType = MailboxConnectorTypes.ExchangeServer, // system to migrate to (type)
ImportSettings = new MailboxConnectorSettingsExchangeServer // system to migrate to (configuration)
{
Url = "https://www.myExchangeServer.com",
ExchangeMailboxArchiveHandling = ExchangeMailboxArchiveHandling.Mailbox
},
ProjectType = ProjectTypes.Mailbox // project type (mailbox)
};
Changes:
Something
classes have been replaced by Something
Configuration classes (see match table in the next section).Something
Configuration classes with appropriate attribute names.// Create the mailbox connector
MailboxConnector mailboxConnector = new MailboxConnector
{
Id = Guid.NewGuid(), // auto-generated if unspecified
Name = "My Example Connector", // connector display name
UserId = ticket.UserId, // own user ID
ExportType = MailboxConnectorTypes.Gmail, // system to migrate from (type)
ExportConfiguration = new ZimbraConfiguration // system to migrate from (configuration)
{
UseAdministrativeCredentials = true,
Url = "https://my.zimbra.server.com",
MigrateSuggestedContacts = true,
AdministrativeUsername = "admin_username", // set admin username
AdministrativePassword = "admin_password" // set admin password
},
ImportType = MailboxConnectorTypes.ExchangeServer, // system to migrate to (type)
ImportConfiguration = new ExchangeConfiguration // system to migrate to (configuration)
{
Url = "https://www.myExchangeServer.com",
ExchangeItemType = ExchangeMailboxArchiveHandling.Mailbox,
AdministrativeUsername = "admin_username", // set admin username
AdministrativePassword = "admin_password" // set admin password
},
ProjectType = ProjectTypes.Mailbox // project type (mailbox)
};
The table below lists all types that have been removed from API v1 and their equivalent in the API v2.
API v1 | API v2 |
---|---|
MailboxConnectorSettingsAws | AwsArchiveConfiguration |
MailboxConnectorSettingsExchangeOnline2 (Mailbox / Archive) | ExchangeConfiguration |
MailboxConnectorSettingsExchangeOnlineChina (Mailbox / Archive) | ExchangeConfiguration |
MailboxConnectorSettingsExchangeServer (Mailbox / Archive) | ExchangeConfiguration |
MailboxConnectorSettingsExchangeOnline2 (Public Folder) | ExchangePublicFolderConfiguration |
MailboxConnectorSettingsExchangeOnlineChina (Public Folder) | ExchangePublicFolderConfiguration |
MailboxConnectorSettingsExchangeServer (Public Folder) | ExchangePublicFolderConfiguration |
MailboxConnectorSettingsGmail | GoogleMailboxConfiguration |
MailboxConnectorSettingsGoogleDrive | GoogleDriveConfiguration |
MailboxConnectorSettingsGoogleVault | GoogleVaultConfiguration |
MailboxConnectorSettingsGroupWise | GroupWiseConfiguration |
MailboxConnectorSettingsImap | HostConfiguration |
MailboxConnectorSettingsLotus | LotusConfiguration |
MailboxConnectorSettingsOneDriveProOnline | OneDriveProConfiguration |
MailboxConnectorSettingsPop | HostConfiguration |
MailboxConnectorSettingsPst | AzurePstConfiguration / PstInternalStorageConfiguration |
MailboxConnectorSettingsZimbra | ZimbraConfiguration |
The following sample scripts show how to perform certain tasks in MigrationWiz through our SOAP APIs.
It is important to note that these scripts use a SoapSampleUtils
class found below, which has a
method ExecuteAndCheck
that wraps the Execute
method exposed by the WebService
class. The
ExecuteAndCheck
method handles all errors that arise from requests. You can write your own variation
of this method to use in your own application.
/// <summary>
/// Represents intro sample code.
/// In this example, we will migrate a mailbox from hotmail into Office 365
/// </summary>
/// <remarks>
/// Snippet reference for https://www.bittitan.com/kb/115008251608 (KB004293).
/// </remarks>
public static class SetUpAndRunMigration
{
/// <summary>
/// Web service.
/// </summary>
private static WebService webService;
/// <summary>
/// Ticket.
/// </summary>
private static Ticket ticket;
/// <summary>
/// Main entry point.
/// </summary>
public static void Run()
{
// Initialize a web service client
Console.WriteLine("Starting to Run");
SetUpAndRunMigration.webService = new WebService
{
Url = "https://www.migrationwiz.com/API/2.0/WebService.asmx"
};
Console.WriteLine("Initialized web service client");
// Get a ticket
SetUpAndRunMigration.ticket = SetUpAndRunMigration.GetTicket("user@domain.com", "password");
Console.WriteLine("Authenticated web service client");
// Create a connector
MailboxConnector mailboxConnector = SetUpAndRunMigration.CreateMailboxConnector();
Console.WriteLine("Created mailbox connector");
// Create a mailbox
Mailbox mailbox = SetUpAndRunMigration.CreateMailbox(
mailboxConnector: mailboxConnector,
sourceEmailAddress: "source@example.com",
sourcePassword: "sourcepassword",
destinationEmailAddress: "destination@example.com",
destinationPassword: "destinationpassword");
Console.WriteLine("Created mailbox");
// Submit the mailbox for migration (full migration using a premium license drawn from the account)
MailboxMigration mailboxMigration = SetUpAndRunMigration.SubmitMailbox(mailbox, MailboxQueueTypes.Full);
Console.WriteLine("Submitted mailbox for migration");
// Wait until the migration completes
SetUpAndRunMigration.WaitUntilCompletion(mailboxMigration);
Console.WriteLine("Completed migration");
}
/// <summary>
/// Gets a ticket used for authentication purposes.
/// </summary>
/// <param name="emailAddress">The email address.</param>
/// <param name="password">The password.</param>
/// <returns>A ticket.</returns>
public static Ticket GetTicket(
string emailAddress,
string password)
{
// Prepare authenticate request
AuthenticateRequest authenticateRequest = new AuthenticateRequest
{
EmailAddress = emailAddress,
Password = password
};
// Perform authenticate request
AuthenticateResponse authenticateResponse =
SetUpAndRunMigration.webService.ExecuteAndCheck<AuthenticateResponse>(authenticateRequest);
// Return ticket from the authenticate response
return authenticateResponse.Ticket;
}
/// <summary>
/// Creates a mailbox connector.
/// In this example, the connector is configured to migrate from Hotmail to Office 365
/// </summary>
/// <returns>A mailbox connector.</returns>
public static MailboxConnector CreateMailboxConnector()
{
// Prepare mailbox connector
MailboxConnector mailboxConnector = new MailboxConnector
{
// Set basic properties
Id = Guid.NewGuid(), // auto-generated if unspecified
Name = "My Example Connector", // connector display name
UserId = SetUpAndRunMigration.ticket.UserId, // own user ID
ExportType = MailboxConnectorTypes.POP, // system to migrate from (type)
ExportConfiguration = new HostConfiguration // system to migrate FROM (configuration)
{
Host = "pop3.live.com"
},
ImportType = MailboxConnectorTypes.ExchangeOnline2, // system to migrate to (type)
ImportConfiguration = new ExchangeConfiguration(), // system to migrate to (configuration)
// Set filtering properties
ItemStartDate = DateTime.MinValue, // do not restrict to a specific start date
ItemEndDate = DateTime.MaxValue, // do not restrict to a specific end date
FolderFilter = null, // do not exclude any folder
Flags = MailboxFlags.None, // do not use advanced options
// Set error properties
ItemRetryTimeout = 60, // on error, first wait 60 seconds, then 120 seconds, etc.
MaximumItemFailures = 100, // fail the migration if more than 100 items failed to migrate
MaximumItemRetry = 3, // retry each item up to 3 times before marking it as failed
// Set purging properties
PurgeNotification = 30, // show a warning 30 days before the purge date
PurgePeriod = 90, // purge the connector 90 days
// Set max transfer properties
MaximumDataTransferRate = long.MaxValue, // no data transfer rate limit
MaximumDataTransferRateDuration = long.MaxValue, // no data transfer rate duration limit
// Set processing properties
MaximumSimultaneousMigrations = 1000, // maximum number of concurrent mailboxes to migrate
ProcessingRequirement = ProcessingRequirements.Any, // do not specify advanced processing requirements
ZoneRequirement = ZoneRequirements.NorthAmerica // do not specify advanced processing requirements
};
// Prepare create request
CreateRequest createRequest = new CreateRequest
{
Ticket = SetUpAndRunMigration.ticket,
Entities = new Entity[] { mailboxConnector }
};
// Perform create request
CreateResponse createResponse =
SetUpAndRunMigration.webService.ExecuteAndCheck<CreateResponse>(createRequest);
mailboxConnector = createResponse.Entities.OfType<MailboxConnector>().First();
// Return mailbox connector
return mailboxConnector;
}
/// <summary>
/// Creates a mailbox.
/// </summary>
/// <param name="mailboxConnector">The mailbox connector.</param>
/// <param name="sourceEmailAddress">The source email address.</param>
/// <param name="sourcePassword">The source password.</param>
/// <param name="destinationEmailAddress">The destination email address.</param>
/// <param name="destinationPassword">The destination password.</param>
/// <returns>A mailbox.</returns>
public static Mailbox CreateMailbox(
MailboxConnector mailboxConnector,
string sourceEmailAddress,
string sourcePassword,
string destinationEmailAddress,
string destinationPassword)
{
// Prepare mailbox
Mailbox mailbox = new Mailbox
{
Id = Guid.NewGuid(), // auto-generated if unspecified
ConnectorId = mailboxConnector.Id, // associate the mailbox with the connector
ExportEmailAddress = sourceEmailAddress, // mailbox to migrate from (email address)
ExportUserName = sourceEmailAddress, // mailbox to migrate from (user name)
ExportPassword = sourcePassword, // mailbox to migrate from (password)
ImportEmailAddress = destinationEmailAddress, // mailbox to migrate to (email address)
ImportUserName = destinationEmailAddress, // mailbox to migrate to (user name)
ImportPassword = destinationPassword, // mailbox to migrate to (password)
FolderFilter = null, // no folder filter
Flags = MailboxFlags.None // no flogs
};
// Prepare create request
CreateRequest createRequest = new CreateRequest
{
Ticket = SetUpAndRunMigration.ticket,
Entities = new Entity[] { mailbox }
};
// Perform create request
CreateResponse createResponse =
SetUpAndRunMigration.webService.ExecuteAndCheck<CreateResponse>(createRequest);
mailbox = createResponse.Entities.OfType<Mailbox>().First();
// Return mailbox
return mailbox;
}
/// <summary>
/// Submits a mailbox for migration.
/// </summary>
/// <param name="mailbox">The mailbox.</param>
/// <param name="mailboxQueueType">The mailbox queue type</param>
/// <returns></returns>
public static MailboxMigration SubmitMailbox(
Mailbox mailbox,
MailboxQueueTypes mailboxQueueType)
{
// Set basic properties
MailboxMigration mailboxMigration = new MailboxMigration
{
Id = Guid.NewGuid(), // auto-generated if unspecified
UserId = SetUpAndRunMigration.ticket.UserId, // own user ID
ConnectorId = mailbox.ConnectorId, // associate the migration submission with the connector
MailboxId = mailbox.Id, // associate the migration submission with the mailbox
Type = mailboxQueueType, // type of migration: trial, full, etc.
MaximumDataTransfer = long.MaxValue, // no data transfer limit
MaximumItemsPerFolder = int.MaxValue, // no data transfer limit
Status = MailboxQueueStatus.Submitted, // must be submitted
Priority = 1 // must be 1
};
// Preare create reqeust
CreateRequest createRequest = new CreateRequest
{
Ticket = SetUpAndRunMigration.ticket,
Entities = new Entity[] { mailboxMigration }
};
// Perform create request
CreateResponse createResponse =
SetUpAndRunMigration.webService.ExecuteAndCheck<CreateResponse>(createRequest);
mailboxMigration = createResponse.Entities.OfType<MailboxMigration>().First();
// Return mailbox migration
return mailboxMigration;
}
/// <summary>
/// Waits until completion.
/// </summary>
/// <param name="mailboxMigration">The mailbox migration.</param>
public static void WaitUntilCompletion(MailboxMigration mailboxMigration)
{
// Prepare retrieve request
RetrieveRequest retrieveRequest = new RetrieveRequest
{
Ticket = SetUpAndRunMigration.ticket,
EntityName = typeof(MailboxMigration).Name,
SearchCondition = new SearchCondition
{
SearchFilters = new SearchFilter[] {
new SearchFilter
{
PropertyName = "Id",
ComparisonOperator = ComparisonOperator.Equal,
Value = mailboxMigration.Id,
}
}
},
Count = 1
};
// Keep retrieving the migration state until complete
while (true)
{
// Perform retrieve reqesut
RetrieveResponse retrieveResponse =
SetUpAndRunMigration.webService.ExecuteAndCheck<RetrieveResponse>(retrieveRequest);
mailboxMigration = retrieveResponse.Entities.OfType<MailboxMigration>().First();
// Print status
switch (mailboxMigration.Status)
{
case MailboxQueueStatus.Completed:
case MailboxQueueStatus.Stopped:
case MailboxQueueStatus.Failed:
case MailboxQueueStatus.MaximumTransferReached:
Console.WriteLine("Done - " + mailboxMigration.Status);
return;
default:
Console.Write("Waiting - " + mailboxMigration.Status);
break;
}
// Do not call too frequently or your account may be locked
const int sleepTime = 60000; // 1 minute
Thread.Sleep(sleepTime);
}
}
}
/// <summary>
/// Represents coupon sample code.
/// </summary>
/// <remarks>
/// Snippet reference for https://www.bittitan.com/kb/115008258748 (KB004970).
/// </remarks>
public static class CouponSample
{
/// <summary>
/// Web service.
/// </summary>
private static WebService webService;
/// <summary>
/// Ticket.
/// </summary>
private static Ticket ticket;
/// <summary>
/// Main entry point.
/// </summary>
public static void Run()
{
// Initialize a web service client
CouponSample.webService = new WebService
{
Url = "https://www.migrationwiz.com/API/2.0/WebService.asmx"
};
// Get a ticket. Replace the username/password with valid entries.
CouponSample.ticket = CouponSample.GetTicket("user@domain.com", "password");
Console.WriteLine("Authenticated web service client");
// Create coupons
Coupon[] coupons = CouponSample.CreateCoupons();
Console.WriteLine("Created coupons");
// List coupons
CouponSample.ListCoupons();
Console.WriteLine("Listed coupons");
// Delete coupons
CouponSample.DeleteCoupons(coupons);
Console.WriteLine("Deleted coupons");
// List coupons
CouponSample.ListCoupons();
Console.WriteLine("Listed coupons");
}
/// <summary>
/// Gets a ticket used for authentication purposes.
/// </summary>
/// <param name="emailAddress">Email address.</param>
/// <param name="password">Password.</param>
/// <returns>Ticket.</returns>
public static Ticket GetTicket(
string emailAddress,
string password)
{
// Prepare authenticate request
AuthenticateRequest authenticateRequest = new AuthenticateRequest
{
EmailAddress = emailAddress,
Password = password
};
// Perform authenticate request
AuthenticateResponse authenticateResponse =
CouponSample.webService.ExecuteAndCheck<AuthenticateResponse>(authenticateRequest);
// Return ticket
return authenticateResponse.Ticket;
}
/// <summary>
/// Creates coupons.
/// </summary>
/// <returns>Coupons.</returns>
public static Coupon[] CreateCoupons()
{
// Define coupons to create Only 10 coupons can be created per create request If many coupons must be
// created, use multiple batched create requests
const int couponCount = 1;
Coupon[] coupons = new Coupon[couponCount];
for (int i = 0; i < couponCount; i++)
{
coupons[i] = new Coupon
{
UserId = CouponSample.ticket.UserId, // required
ProductSkuId = MigrationProxy.ProductSkuValues.Mailbox, // mailbox license
Quantity = 1, // 1 coupon = 1 license
ExpireDate = new DateTime(2013, 01, 01), // must be used before 01/01/13
Validity = 30, // must be used within 30 days of redemption
Label = "My Coupon Project", // note for tracking purposes
};
}
// Prepare create request
CreateRequest createRequest = new CreateRequest
{
Ticket = CouponSample.ticket,
Entities = coupons
};
// Perform create request
CreateResponse createResponse =
CouponSample.webService.ExecuteAndCheck<CreateResponse>(createRequest);
coupons = createResponse.Entities.OfType<Coupon>().ToArray();
// Return coupons having codes ready to be used
return coupons;
}
/// <summary>
/// Delete coupons.
/// </summary>
/// <param name="coupons">Coupons.</param>
public static void DeleteCoupons(Coupon[] coupons)
{
// Define coupons to delete Only 10 coupons can be deleted per delete request If many coupons must be
// deleted, use multiple batched delete requests
EntityTarget[] deleteTargets = new EntityTarget[coupons.Length];
for (int i = 0; i < coupons.Length; i++)
{
EntityTarget deleteTarget = new EntityTarget();
deleteTarget.Id = coupons[i].Id;
deleteTarget.EntityName = typeof(Coupon).Name;
deleteTargets[i] = deleteTarget;
}
// Delete coupons An error will be returned for coupons that have been redeemed Otherwise licenses will be
// restored to the account and the coupon code will be deleted
DeleteRequest deleteRequest = new DeleteRequest
{
Ticket = CouponSample.ticket,
EntityTargets = deleteTargets
};
// Perform delete request
CouponSample.webService.ExecuteAndCheck<DeleteResponse>(deleteRequest);
}
/// <summary>
/// Lists coupons.
/// </summary>
public static void ListCoupons()
{
// Prepare a retrieve request In this example, only retrieve coupons created later than 1 year ago Complex
// conditions (include multi-level and/or conditions) can also be used, as well as sorting and aggregates
RetrieveRequest retrieveRequest = new RetrieveRequest
{
Ticket = CouponSample.ticket,
EntityName = typeof(Coupon).Name,
SearchCondition = new SearchCondition
{
SearchFilters = new SearchFilter[]
{
new SearchFilter
{
PropertyName = "CreateDate",
ComparisonOperator = ComparisonOperator.Greater,
Value = DateTime.UtcNow.AddYears(-1)
}
}
},
Count = 100 // cannot retrieve more than 100 at a time
};
// Keep retrieving coupons with paging
for (int i = 0; i < int.MaxValue; i++)
{
retrieveRequest.Offset = i * retrieveRequest.Count; // paging offset: 0, then 100, then 200, etc.
RetrieveResponse retrieveResponse =
CouponSample.webService.ExecuteAndCheck<RetrieveResponse>(retrieveRequest);
foreach (Coupon coupon in retrieveResponse.Entities)
{
// Write a few properties
Console.WriteLine("Code: " + coupon.Code);
Console.WriteLine("Used: " + (Guid.Empty == coupon.ActivationUserId));
Console.WriteLine("Expires: " + coupon.ExpireDate.ToLocalTime());
Console.WriteLine();
}
if (retrieveResponse.Entities.Length < retrieveRequest.Count)
break; // done paging
}
}
}
/// <summary>
/// Defines soap sample utilities.
/// </summary>
public static class SoapSampleUtils
{
/// <summary>
/// Executes a request and checks the result.
/// </summary>
/// <param name="request">Request.</param>
/// <returns>Typed response.</returns>
public static T ExecuteAndCheck<T>(
this WebService webService,
Request request)
where T : Response
{
// Execute the request
Response response = webService.Execute(request);
// Check the response
return SoapSampleUtils.CheckResponse<T>(response);
}
/// <summary>
/// Checks that a response is of the specified type and also fully succeeded.
/// </summary>
/// <param name="response">Response.</param>
/// <returns>Typed response.</returns>
public static T CheckResponse<T>(Response response)
where T : Response
{
// This routine provides simple error checking Additional properties
// (ex: ErrorCode) are available for troubleshooting
// Check if the entire request failed
FailureResponse failureResponse = response as FailureResponse;
if (null != failureResponse)
{
string message = failureResponse.ProcessingError.Message;
Console.WriteLine(message);
throw new ApplicationException(message);
}
// Check if the response is of a type we did not expect
T typedResponse = response as T;
if (null == typedResponse)
{
string message = "Bad response.";
Console.WriteLine(message);
throw new ApplicationException(message);
}
// Check if a create request had any partial failure
CreateResponse createResponse = response as CreateResponse;
if ((null != createResponse) &&
(null != createResponse.ProcessingErrors) &&
(0 < createResponse.ProcessingErrors.Length))
{
foreach (ProcessingError processingError in createResponse.ProcessingErrors)
Console.WriteLine("Create failure: " + processingError.Message);
string message = "Create failed.";
throw new ApplicationException(message);
}
// Check if an update request had any partial failure
UpdateResponse updateResponse = response as UpdateResponse;
if ((null != updateResponse) &&
(null != updateResponse.ProcessingErrors) &&
(0 < updateResponse.ProcessingErrors.Length))
{
foreach (ProcessingError processingError in updateResponse.ProcessingErrors)
Console.WriteLine("Update failure: " + processingError.Message);
string message = "Update failed.";
throw new ApplicationException(message);
}
// Check if a delete request had any partial failure
DeleteResponse deleteResponse = response as DeleteResponse;
if ((null != deleteResponse) &&
(null != deleteResponse.ProcessingErrors) &&
(0 < deleteResponse.ProcessingErrors.Length))
{
foreach (ProcessingError processingError in deleteResponse.ProcessingErrors)
Console.WriteLine("Delete failure: " + processingError.Message);
string message = "Delete failed.";
throw new ApplicationException(message);
}
// Returned the typed response
return typedResponse;
}
}