Class XperiflowStorageClient
Namespace: Workspace.XBR.Xperiflow.Core.RestApi.Storage
Assembly: Xperiflow.dll
public class XperiflowStorageClient : IXperiflowStorageClient
Implements: Workspace.XBR.Xperiflow.Core.RestApi.Storage.IXperiflowStorageClient
Properties
JsonSerializerSettings
protected JsonSerializerSettings JsonSerializerSettings { get; }
ReadResponseAsString
public bool ReadResponseAsString { get; set; }
Methods
GetDatabaseNamesResourceAsync(XperiflowSessionInfo, MemoizedCacheInfo?, CancellationToken)
DatabaseNamesResource
public virtual Task<GetDatabaseNamesResourceResponseContext> GetDatabaseNamesResourceAsync(XperiflowSessionInfo x_OS_SessionInfo, MemoizedCacheInfo? cacheInfo = null, CancellationToken cancellationToken = default)
Remarks
Get names of the databases in the elastic pool
Returns
Task
< Workspace.XBR.Xperiflow.Core.RestApi.Storage.GetDatabaseNamesResourceResponseContext >
ok
Parameters
Type | Name | Description |
---|---|---|
Workspace.XBR.Xperiflow.Core.Session.XperiflowSessionInfo | x_OS_SessionInfo | OneStream session info header object. |
Workspace.XBR.Xperiflow.Utilities.Http.MemoizedCacheInfo | cacheInfo | |
System.Threading.CancellationToken | cancellationToken | A cancellation token that can be used by other objects or threads to receive notice of cancellation. |
Exceptions
Workspace.XBR.Xperiflow.Core.RestApi.Exceptions.XperiflowApiException A server side error occurred.
GetDatabaseSizeFragmentationResourceAsync(XperiflowSessionInfo, string, string, IEnumerable<string>?, string?, int?, int?, string?, MemoizedCacheInfo?, CancellationToken)
DatabaseSizeFragmentationResource
public virtual Task<GetDatabaseSizeFragmentationResourceResponseContext> GetDatabaseSizeFragmentationResourceAsync(XperiflowSessionInfo x_OS_SessionInfo, string database_resource, string database_schema, IEnumerable<string>? fields = null, string? filter = null, int? page = null, int? records_per_page = null, string? order_bys = null, MemoizedCacheInfo? cacheInfo = null, CancellationToken cancellationToken = default)
Remarks
Gets a information in relation to a database by project id. If no project id is supplied, it will get info from the DataSense_Framework database instead of a project.
Body Params:
- project_id Optional(guid) The project unique identifier.
Returns:
-
project_id Optional(str): The project unique identifier.
-
database_resource (str): The project unique resource identifier
-
database_schema (str): The project unique schema identifier
-
database_current_size_datatable (DataTableContext): A datatable containing two columns
-
database_name (str): the database schema
-
database_size (str): the database size
-
database_size_limit_datatable (DataTableContext): A single column datatable containing the max size in bytes
-
DatabaseDataMaxSizeInBytes (float)
-
fragmentation_datatable (DataTableContext): A datatable containing relevant fragmentation information. Columns include:
-
Table (str)
-
Index (str)
-
partition_number (int)
-
fragmentation_percent (float)
-
page_count (int)
Returns
Task
< Workspace.XBR.Xperiflow.Core.RestApi.Storage.GetDatabaseSizeFragmentationResourceResponseContext >
ok
Parameters
Type | Name | Description |
---|---|---|
Workspace.XBR.Xperiflow.Core.Session.XperiflowSessionInfo | x_OS_SessionInfo | OneStream session info header object. |
System.String | database_resource | the database resource. |
System.String | database_schema | the database schema. |
System.Collections.Generic.IEnumerable<System.String> | fields | A json list of column names to return in the request. |
System.String | filter | A json dictionary of a filter statement. |
System.Nullable<System.Int32> | page | The page to return if using pagination. |
System.Nullable<System.Int32> | records_per_page | The amount of records per page to return if using pagination. |
System.String | order_bys | A json dictionary containing an order by statement. |
Workspace.XBR.Xperiflow.Utilities.Http.MemoizedCacheInfo | cacheInfo | |
System.Threading.CancellationToken | cancellationToken | A cancellation token that can be used by other objects or threads to receive notice of cancellation. |
Exceptions
Workspace.XBR.Xperiflow.Core.RestApi.Exceptions.XperiflowApiException A server side error occurred.
PostDatabaseCleanupResourceAsync(XperiflowSessionInfo, BodyCleanupContext, MemoizedCacheInfo?, CancellationToken)
DatabaseCleanupResource
public virtual Task<NullableIntItemsIdentifierXperiflowResponseContext> PostDatabaseCleanupResourceAsync(XperiflowSessionInfo x_OS_SessionInfo, BodyCleanupContext body, MemoizedCacheInfo? cacheInfo = null, CancellationToken cancellationToken = default)
Remarks
Commits a Feature DataSource to the BuildInfo. Note that there are only certain states of the Build that this is an allowed action.
Body Params:
-
project_ids (List/[str
{guid}
/], optional): The project unique identifiers you would like to add jobs to. If a list of project ids are not given, this api is limited to only reorganizing the framework database. -
clean_types (List/[str/]): The clean types you would like to include for each project.
-
Choices:
-
"old_data_removal" - Will clean up prediction and pipeline data
-
"data_reorganize" - Will do an index rebuild
-
-
include_framework (bool): Whether to include the framework database when doing an index rebuild. This will only execute if you include "data_reorganize" in your clean types.
Returns:
-
job_ids (List/[int/]): The list of new job_ids that have been inserted as a result of the post
-
modified: (bool): whether the post modified anything successfully
-
message (str): Will tell you if the job(s) were successfully inserted, or will include error if unsuccessful.
Returns
Task
< Workspace.XBR.Xperiflow.Core.RestApi.Storage.NullableIntItemsIdentifierXperiflowResponseContext >
ok
Parameters
Type | Name | Description |
---|---|---|
Workspace.XBR.Xperiflow.Core.Session.XperiflowSessionInfo | x_OS_SessionInfo | OneStream session info header object. |
Workspace.XBR.Xperiflow.Core.RestApi.Storage.BodyCleanupContext | body | |
Workspace.XBR.Xperiflow.Utilities.Http.MemoizedCacheInfo | cacheInfo | |
System.Threading.CancellationToken | cancellationToken | A cancellation token that can be used by other objects or threads to receive notice of cancellation. |
Exceptions
Workspace.XBR.Xperiflow.Core.RestApi.Exceptions.XperiflowApiException A server side error occurred.
GetMetaFileInfoResourceResourceAsync(XperiflowSessionInfo, string, string, MemoizedCacheInfo?, CancellationToken)
MetaFileInfoResource
public virtual Task<GetMetaFileInfoResourceResponseContext> GetMetaFileInfoResourceResourceAsync(XperiflowSessionInfo x_OS_SessionInfo, string path, string connection_key_reference, MemoizedCacheInfo? cacheInfo = null, CancellationToken cancellationToken = default)
Remarks
API dedicated to retrieving file metadata.
Returns
Task
< Workspace.XBR.Xperiflow.Core.RestApi.Storage.GetMetaFileInfoResourceResponseContext >
ok
Parameters
Type | Name | Description |
---|---|---|
Workspace.XBR.Xperiflow.Core.Session.XperiflowSessionInfo | x_OS_SessionInfo | OneStream session info header object. |
System.String | path | The path to the file. |
System.String | connection_key_reference | The filesystem metadata connection key reference. |
Workspace.XBR.Xperiflow.Utilities.Http.MemoizedCacheInfo | cacheInfo | |
System.Threading.CancellationToken | cancellationToken | A cancellation token that can be used by other objects or threads to receive notice of cancellation. |
Exceptions
Workspace.XBR.Xperiflow.Core.RestApi.Exceptions.XperiflowApiException A server side error occurred.
DeleteMetaFileInfoResourceAsync(XperiflowSessionInfo, string, string, MemoizedCacheInfo?, CancellationToken)
MetaFileInfoResource
public virtual Task<NullDataXperiflowResponseContext> DeleteMetaFileInfoResourceAsync(XperiflowSessionInfo x_OS_SessionInfo, string path, string connection_key_reference, MemoizedCacheInfo? cacheInfo = null, CancellationToken cancellationToken = default)
Remarks
API dedicated to deleting file metadata.
Returns
Task
< Workspace.XBR.Xperiflow.Core.RestApi.Storage.NullDataXperiflowResponseContext >
ok
Parameters
Type | Name | Description |
---|---|---|
Workspace.XBR.Xperiflow.Core.Session.XperiflowSessionInfo | x_OS_SessionInfo | OneStream session info header object. |
System.String | path | The path to the file. |
System.String | connection_key_reference | The filesystem metadata connection key reference. |
Workspace.XBR.Xperiflow.Utilities.Http.MemoizedCacheInfo | cacheInfo | |
System.Threading.CancellationToken | cancellationToken | A cancellation token that can be used by other objects or threads to receive notice of cancellation. |
Exceptions
Workspace.XBR.Xperiflow.Core.RestApi.Exceptions.XperiflowApiException A server side error occurred.
GetMetaDirectoryInfoResourceAsync(XperiflowSessionInfo, string, string, bool?, int?, bool?, MemoizedCacheInfo?, CancellationToken)
MetaDirectoryInfoResource
public virtual Task<GetMetaDirectoryInfoResourceResponseContext> GetMetaDirectoryInfoResourceAsync(XperiflowSessionInfo x_OS_SessionInfo, string path, string connection_key_reference, bool? include_sub_content_metadata = null, int? max_depth = null, bool? with_dirs = null, MemoizedCacheInfo? cacheInfo = null, CancellationToken cancellationToken = default)
Remarks
API dedicated to retrieving directory metadata.
Returns
Task
< Workspace.XBR.Xperiflow.Core.RestApi.Storage.GetMetaDirectoryInfoResourceResponseContext >
ok
Parameters
Type | Name | Description |
---|---|---|
Workspace.XBR.Xperiflow.Core.Session.XperiflowSessionInfo | x_OS_SessionInfo | OneStream session info header object. |
System.String | path | The path to the file. |
System.String | connection_key_reference | The filesystem metadata connection key reference. |
System.Nullable<System.Boolean> | include_sub_content_metadata | To include or not include the sub content metadata within a directory. |
System.Nullable<System.Int32> | max_depth | How deep the sub content metadata should traverse for info. |
System.Nullable<System.Boolean> | with_dirs | Whether to include directories, or just files in sub content metadata. |
Workspace.XBR.Xperiflow.Utilities.Http.MemoizedCacheInfo | cacheInfo | |
System.Threading.CancellationToken | cancellationToken | A cancellation token that can be used by other objects or threads to receive notice of cancellation. |
Exceptions
Workspace.XBR.Xperiflow.Core.RestApi.Exceptions.XperiflowApiException A server side error occurred.
PostMetaDirectoryInfoResourceAsync(XperiflowSessionInfo, BodyMetaDirectoryInfoContext, string, MemoizedCacheInfo?, CancellationToken)
MetaDirectoryInfoResource
public virtual Task<NullDataXperiflowResponseContext> PostMetaDirectoryInfoResourceAsync(XperiflowSessionInfo x_OS_SessionInfo, BodyMetaDirectoryInfoContext body, string connection_key_reference, MemoizedCacheInfo? cacheInfo = null, CancellationToken cancellationToken = default)
Remarks
Creates a directory at a specified path.
Returns
Task
< Workspace.XBR.Xperiflow.Core.RestApi.Storage.NullDataXperiflowResponseContext >
ok
Parameters
Type | Name | Description |
---|---|---|
Workspace.XBR.Xperiflow.Core.Session.XperiflowSessionInfo | x_OS_SessionInfo | OneStream session info header object. |
Workspace.XBR.Xperiflow.Core.RestApi.Storage.BodyMetaDirectoryInfoContext | body | |
System.String | connection_key_reference | The filesystem metadata connection key reference. |
Workspace.XBR.Xperiflow.Utilities.Http.MemoizedCacheInfo | cacheInfo | |
System.Threading.CancellationToken | cancellationToken | A cancellation token that can be used by other objects or threads to receive notice of cancellation. |
Exceptions
Workspace.XBR.Xperiflow.Core.RestApi.Exceptions.XperiflowApiException A server side error occurred.
DeleteMetaDirectoryInfoResourceAsync(XperiflowSessionInfo, string, string, bool?, int?, MemoizedCacheInfo?, CancellationToken)
MetaDirectoryInfoResource
public virtual Task<NullDataXperiflowResponseContext> DeleteMetaDirectoryInfoResourceAsync(XperiflowSessionInfo x_OS_SessionInfo, string path, string connection_key_reference, bool? recursive = null, int? max_depth = null, MemoizedCacheInfo? cacheInfo = null, CancellationToken cancellationToken = default)
Remarks
API dedicated to retrieving directory metadata.
Returns
Task
< Workspace.XBR.Xperiflow.Core.RestApi.Storage.NullDataXperiflowResponseContext >
ok
Parameters
Type | Name | Description |
---|---|---|
Workspace.XBR.Xperiflow.Core.Session.XperiflowSessionInfo | x_OS_SessionInfo | OneStream session info header object. |
System.String | path | The path to the file. |
System.String | connection_key_reference | The filesystem metadata connection key reference. |
System.Nullable<System.Boolean> | recursive | Whether the operation is recursive. |
System.Nullable<System.Int32> | max_depth | How deep the sub content metadata should traverse for info. |
Workspace.XBR.Xperiflow.Utilities.Http.MemoizedCacheInfo | cacheInfo | |
System.Threading.CancellationToken | cancellationToken | A cancellation token that can be used by other objects or threads to receive notice of cancellation. |
Exceptions
Workspace.XBR.Xperiflow.Core.RestApi.Exceptions.XperiflowApiException A server side error occurred.
GetMetaFileContentReferenceResourceAsync(XperiflowSessionInfo, string, string, bool?, MemoizedCacheInfo?, CancellationToken)
MetaFileContentReferenceResource
public virtual Task<GetMetaFileContentReferenceResourceResponseContext> GetMetaFileContentReferenceResourceAsync(XperiflowSessionInfo x_OS_SessionInfo, string path, string connection_key_reference, bool? as_ephemeral = null, MemoizedCacheInfo? cacheInfo = null, CancellationToken cancellationToken = default)
Remarks
API dedicated to retrieving file content references.
Returns
Task
< Workspace.XBR.Xperiflow.Core.RestApi.Storage.GetMetaFileContentReferenceResourceResponseContext >
ok
Parameters
Type | Name | Description |
---|---|---|
Workspace.XBR.Xperiflow.Core.Session.XperiflowSessionInfo | x_OS_SessionInfo | OneStream session info header object. |
System.String | path | The path to the file. |
System.String | connection_key_reference | The filesystem metadata connection key reference. |
System.Nullable<System.Boolean> | as_ephemeral | If the file should be treated as ephemeral. |
Workspace.XBR.Xperiflow.Utilities.Http.MemoizedCacheInfo | cacheInfo | |
System.Threading.CancellationToken | cancellationToken | A cancellation token that can be used by other objects or threads to receive notice of cancellation. |
Exceptions
Workspace.XBR.Xperiflow.Core.RestApi.Exceptions.XperiflowApiException A server side error occurred.
GetMetaFileContentStreamResourceAsync(XperiflowSessionInfo, string, string, int?, MemoizedCacheInfo?, CancellationToken)
MetaFileContentStreamResource
public virtual Task<FileResponse> GetMetaFileContentStreamResourceAsync(XperiflowSessionInfo x_OS_SessionInfo, string path, string connection_key_reference, int? content_size = null, MemoizedCacheInfo? cacheInfo = null, CancellationToken cancellationToken = default)
Remarks
API dedicated to retrieving file content references.
Returns
Task
< Workspace.XBR.Xperiflow.Core.RestApi.Storage.FileResponse >
ok
Parameters
Type | Name | Description |
---|---|---|
Workspace.XBR.Xperiflow.Core.Session.XperiflowSessionInfo | x_OS_SessionInfo | OneStream session info header object. |
System.String | path | The path to the file. |
System.String | connection_key_reference | The filesystem metadata connection key reference. |
System.Nullable<System.Int32> | content_size | The content size to return of the file. Use this for preview. |
Workspace.XBR.Xperiflow.Utilities.Http.MemoizedCacheInfo | cacheInfo | |
System.Threading.CancellationToken | cancellationToken | A cancellation token that can be used by other objects or threads to receive notice of cancellation. |
Exceptions
Workspace.XBR.Xperiflow.Core.RestApi.Exceptions.XperiflowApiException A server side error occurred.
PostMetaFileContentWriteStartResourceAsync(XperiflowSessionInfo, BodyMetadataWriteStartContext, string, MemoizedCacheInfo?, CancellationToken)
MetaFileContentWriteStartResource
public virtual Task<PostMetaFileContentWriteStartResourceResponseContext> PostMetaFileContentWriteStartResourceAsync(XperiflowSessionInfo x_OS_SessionInfo, BodyMetadataWriteStartContext body, string connection_key_reference, MemoizedCacheInfo? cacheInfo = null, CancellationToken cancellationToken = default)
Remarks
API dedicated to initializing a write to the content storage of meta filesystem.
Returns
Task
< Workspace.XBR.Xperiflow.Core.RestApi.Storage.PostMetaFileContentWriteStartResourceResponseContext >
ok
Parameters
Type | Name | Description |
---|---|---|
Workspace.XBR.Xperiflow.Core.Session.XperiflowSessionInfo | x_OS_SessionInfo | OneStream session info header object. |
Workspace.XBR.Xperiflow.Core.RestApi.Storage.BodyMetadataWriteStartContext | body | |
System.String | connection_key_reference | The filesystem metadata connection key reference. |
Workspace.XBR.Xperiflow.Utilities.Http.MemoizedCacheInfo | cacheInfo | |
System.Threading.CancellationToken | cancellationToken | A cancellation token that can be used by other objects or threads to receive notice of cancellation. |
Exceptions
Workspace.XBR.Xperiflow.Core.RestApi.Exceptions.XperiflowApiException A server side error occurred.
PostMetaFileContentWriteUndoStartResourceAsync(XperiflowSessionInfo, BodyMetadataWriteStartUndoContext, string, MemoizedCacheInfo?, CancellationToken)
MetaFileContentWriteUndoStartResource
public virtual Task<NullDataXperiflowResponseContext> PostMetaFileContentWriteUndoStartResourceAsync(XperiflowSessionInfo x_OS_SessionInfo, BodyMetadataWriteStartUndoContext body, string connection_key_reference, MemoizedCacheInfo? cacheInfo = null, CancellationToken cancellationToken = default)
Remarks
API dedicated to undoing an initialized write to the content storage of meta filesystem.
Returns
Task
< Workspace.XBR.Xperiflow.Core.RestApi.Storage.NullDataXperiflowResponseContext >
ok
Parameters
Type | Name | Description |
---|---|---|
Workspace.XBR.Xperiflow.Core.Session.XperiflowSessionInfo | x_OS_SessionInfo | OneStream session info header object. |
Workspace.XBR.Xperiflow.Core.RestApi.Storage.BodyMetadataWriteStartUndoContext | body | |
System.String | connection_key_reference | The filesystem metadata connection key reference. |
Workspace.XBR.Xperiflow.Utilities.Http.MemoizedCacheInfo | cacheInfo | |
System.Threading.CancellationToken | cancellationToken | A cancellation token that can be used by other objects or threads to receive notice of cancellation. |
Exceptions
Workspace.XBR.Xperiflow.Core.RestApi.Exceptions.XperiflowApiException A server side error occurred.
PostMetaFileContentWriteResourceAsync(XperiflowSessionInfo, BodyMetadataWriteContext, string, MemoizedCacheInfo?, CancellationToken)
MetaFileContentWriteResource
public virtual Task<NullDataXperiflowResponseContext> PostMetaFileContentWriteResourceAsync(XperiflowSessionInfo x_OS_SessionInfo, BodyMetadataWriteContext body, string connection_key_reference, MemoizedCacheInfo? cacheInfo = null, CancellationToken cancellationToken = default)
Remarks
API dedicated to writing data to the content storage of meta filesystem.
Returns
Task
< Workspace.XBR.Xperiflow.Core.RestApi.Storage.NullDataXperiflowResponseContext >
ok
Parameters
Type | Name | Description |
---|---|---|
Workspace.XBR.Xperiflow.Core.Session.XperiflowSessionInfo | x_OS_SessionInfo | OneStream session info header object. |
Workspace.XBR.Xperiflow.Core.RestApi.Storage.BodyMetadataWriteContext | body | |
System.String | connection_key_reference | The filesystem metadata connection key reference. |
Workspace.XBR.Xperiflow.Utilities.Http.MemoizedCacheInfo | cacheInfo | |
System.Threading.CancellationToken | cancellationToken | A cancellation token that can be used by other objects or threads to receive notice of cancellation. |
Exceptions
Workspace.XBR.Xperiflow.Core.RestApi.Exceptions.XperiflowApiException A server side error occurred.
PostMetaFileContentWriteCommitResourceAsync(XperiflowSessionInfo, BodyMetadataWriteCommitContext, string, MemoizedCacheInfo?, CancellationToken)
MetaFileContentWriteCommitResource
public virtual Task<NullDataXperiflowResponseContext> PostMetaFileContentWriteCommitResourceAsync(XperiflowSessionInfo x_OS_SessionInfo, BodyMetadataWriteCommitContext body, string connection_key_reference, MemoizedCacheInfo? cacheInfo = null, CancellationToken cancellationToken = default)
Remarks
API dedicated to committing the written data to the content storage of meta filesystem.
Returns
Task
< Workspace.XBR.Xperiflow.Core.RestApi.Storage.NullDataXperiflowResponseContext >
ok
Parameters
Type | Name | Description |
---|---|---|
Workspace.XBR.Xperiflow.Core.Session.XperiflowSessionInfo | x_OS_SessionInfo | OneStream session info header object. |
Workspace.XBR.Xperiflow.Core.RestApi.Storage.BodyMetadataWriteCommitContext | body | |
System.String | connection_key_reference | The filesystem metadata connection key reference. |
Workspace.XBR.Xperiflow.Utilities.Http.MemoizedCacheInfo | cacheInfo | |
System.Threading.CancellationToken | cancellationToken | A cancellation token that can be used by other objects or threads to receive notice of cancellation. |
Exceptions
Workspace.XBR.Xperiflow.Core.RestApi.Exceptions.XperiflowApiException A server side error occurred.
PostMetaDBParsingResourceAsync(XperiflowSessionInfo, BodyMetaDbParsingContext, MemoizedCacheInfo?, CancellationToken)
MetaDBParsingResource
public virtual Task<PostMetadbParseResponseContext> PostMetaDBParsingResourceAsync(XperiflowSessionInfo x_OS_SessionInfo, BodyMetaDbParsingContext body, MemoizedCacheInfo? cacheInfo = null, CancellationToken cancellationToken = default)
Remarks
API dedicated to converting sql queries using short hand paths (routine://...) to their corresponding azure container paths.
Returns
Task
< Workspace.XBR.Xperiflow.Core.RestApi.Storage.PostMetadbParseResponseContext >
created
Parameters
Type | Name | Description |
---|---|---|
Workspace.XBR.Xperiflow.Core.Session.XperiflowSessionInfo | x_OS_SessionInfo | OneStream session info header object. |
Workspace.XBR.Xperiflow.Core.RestApi.Storage.BodyMetaDbParsingContext | body | |
Workspace.XBR.Xperiflow.Utilities.Http.MemoizedCacheInfo | cacheInfo | |
System.Threading.CancellationToken | cancellationToken | A cancellation token that can be used by other objects or threads to receive notice of cancellation. |
Exceptions
Workspace.XBR.Xperiflow.Core.RestApi.Exceptions.XperiflowApiException A server side error occurred.
ReadObjectResponseAsync<T>(HttpResponseMessage, IReadOnlyDictionary<string, IEnumerable<string>>, CancellationToken)
protected virtual Task<XperiflowStorageClient.ObjectResponseResult<T>> ReadObjectResponseAsync<T>(HttpResponseMessage response, IReadOnlyDictionary<string, IEnumerable<string>> headers, CancellationToken cancellationToken)
Returns
Task<Workspace.XBR.Xperiflow.Core.RestApi.Storage.XperiflowStorageClient.ObjectResponseResult{{T}}>
Parameters
Type | Name |
---|---|
System.Net.Http.HttpResponseMessage | response |
System.Collections.Generic.IReadOnlyDictionary<System.String,System.Collections.Generic.IEnumerable{System.String}> | headers |
System.Threading.CancellationToken | cancellationToken |
Type Parameters
T
Implements
Inherited Members
System.Object.Equals(System.Object)
System.Object.Equals(System.Object,System.Object)
System.Object.GetHashCode
System.Object.GetType
System.Object.MemberwiseClone
System.Object.ReferenceEquals(System.Object,System.Object)
System.Object.ToString