Current server time: 2017-03-29T10:59:54

Description

This is an API for developing services that use the solutions provided by Signere.no. It is designed to be easy to use, while maintaining security. The API is open to all users of Signere.no, and consists of both a platform independent REST API and a client code library in .NET. The code library is available as a NuGet package for .Net 4.0 and .Net 3.5, and can be downloaded here: 4.0 version, 3.5 version. We also have a VB6 client library, you can read more about it here to download it here: VB6 library.

In the other tabs above, documentation follows for the resources provided by the REST API, as well as information about which http headers that are required in order to make valid requests to the API. Also, all requests must be supplied with a token to authenticate the user. This token must be generated in a specific way. In the security tab it is explained how to generate this token, and there is an example in pseudocode of how to implement the generation.

In the tab with client code examples, we use the .NET client library to perform some basic operations on a document.

REST methods

Click on the resource name to expand.

DescriptionRequired/OptionalDocumentation
POST https://api.signere.no/api/ApiToken/RenewPrimaryKey?OldPrimaryKey={OldPrimaryKey} Renews the primary API key. Generates, sets and returns a new primary API key.
POST https://api.signere.no/api/ApiToken/RenewSecondaryKey?OldSecondaryKey={OldSecondaryKey} Renews the secondary API key. Generates, sets and returns a new secondary API key.
POST https://api.signere.no/api/ApiToken/OTP/RenewPrimaryKeyStep2/Provider/{ProviderId}/OTPCode/{OTPCode} Generates a new primary key and returns it.
PUT https://api.signere.no/api/ApiToken/OTP/RenewPrimaryKeyStep1 Sends an OTP code in an SMS to the given mobile number (the input parameter) to be used in RenewPrimaryKeyOTPStep2 for renewing the primary API key. Use this method when the original primary API key is lost or unrecoverable.
DescriptionRequired/OptionalDocumentation
GET https://api.signere.no/api/Document/SignUrl?documentId={documentId}&signeeRefId={signeeRefId} Returns the url to sign the document for the given Signeeref or the first Signeeref if not SigneerefId is specified
GET https://api.signere.no/api/Document/{DocumentId} Retrieves the document with the given ID.
GET https://api.signere.no/api/Document/SignedDocument/TemporaryViewerUrl/{DocumentId} Returns a temporary URL for viewing a signed document in the BankID applet.
GET https://api.signere.no/api/Document?Status={Status}&Fromdate={Fromdate}&JobId={JobId}&CreatedAfter={CreatedAfter}&ExternalCustomerRef={ExternalCustomerRef} Retrieves a list of documents base on the given parameters. All parameters are optional when not specifying any parameters the 200 last documents will be returned.
POST https://api.signere.no/api/Document Creates a new document to sign, and returns a document response object (including the generated document ID). Remark: To create a new document, one must assign an already existing document job to it or generate a new one.
POST https://api.signere.no/api/Document/CancelDocument Cancels the given document (the document is then still available for the signee, but no longer marked as ready for signature). Remark: if using Json, a GUID must not contain dashes (-), unlike XML.
PUT https://api.signere.no/api/Document/ChangeDeadline Changes the signature deadline for a given document (after expiration date, the receiver is no longer allowed to sign the document).
DescriptionRequired/OptionalDocumentation
POST https://api.signere.no/api/DocumentConvert Converts documents (doc, docx, txt, rtf and openoffice documents to PDF. Uses multipart form upload (ordinary http file upload)
DescriptionRequired/OptionalDocumentation
GET https://api.signere.no/api/DocumentFile/Signed/{DocumentId} Returns the signed document as a file. Filename formatted as: {DocumentId}.sdo
GET https://api.signere.no/api/DocumentFile/Unsigned/{DocumentId} Returns the unsigned document as a file. Filename formatted as: {DocumentId}.pdf
GET https://api.signere.no/api/DocumentFile/SignedPDF/{DocumentId} Returns the signed pdf document as a file. Filename formatted as: {DocumentId}.pdf
POST https://api.signere.no/api/DocumentFile/TempUrl Creates a temporary url to a document (PDF, SDO, and more) that expires at a certain datetime
DescriptionRequired/OptionalDocumentation
GET https://api.signere.no/api/DocumentJob/{jobid} Retrieves a document job in the form of a response object containing the document job parameters. Remark: if using Json, a GUID must not contain dashes (-), unlike XML.
POST https://api.signere.no/api/DocumentJob Creates a document job (every document must be assigned to a document job). Returns the ID (GUID) for the created document job.
DescriptionRequired/OptionalDocumentation
GET https://api.signere.no/api/DocumentProvider/{ProviderId} Retrieves a document provider account (information such as the provider's username, billing address etc). Remark: if using Json, a GUID must not contain dashes (-), unlike XML.
GET https://api.signere.no/api/DocumentProvider/CertificateExpires Gets the expires date for your BankID certificate. If you don't have your own BankID certificate it will return Bad request.
GET https://api.signere.no/api/DocumentProvider/quota/prepaid?ProviderId={ProviderId} Retrieves usage for this account when using av prepaid account, what used, whats left
GET https://api.signere.no/api/DocumentProvider/quota/demo?ProviderId={ProviderId} Retrieves usage for this account when using av demo account, what used, whats left
POST https://api.signere.no/api/DocumentProvider Creates a new document provider (account for submitting documents). Returns the account ID and the primary and secondary API keys.
PUT https://api.signere.no/api/DocumentProvider Updates the information stored in a given document provider account, such as the billing address, logo file etc. Note that in contrast to the DocumentProvider POST method to create a document provider account, only the provider ID is required in this method. Only non-empty fields are updated. Remark: if using Json, a GUID must not contain dashes (-), unlike XML.
DescriptionRequired/OptionalDocumentation
GET https://api.signere.no/api/events/encryptionkey Returns the EventsQueue encryptionKey as a base64 encoded string
DescriptionRequired/OptionalDocumentation
GET https://api.signere.no/api/ExternalLogin/{RequestId} Return the login information from the login
POST https://api.signere.no/api/ExternalLogin DEPRECATED! See SignereID Creates a external login reqest, and returns a url. This url can be used in an iFrame (if the iFrame property is set) or redirect to. Example url: https://secure.signere.no/bankid/ExternalLogin/EE162D59-3AC8-47DD-B5AF-AE50E9F3959A the guid is the requstid. To detect if user is on a mobile device check out http://detectmobilebrowsers.com/. To check for tablet add check for ipad/android or mobile in the useragent string. The login will automaticly get status LOGINTIMEDOUT 5 minutes after successfull login BankID mobile is the only BankID type that is supported if javascript is disabled in the browser. Use this javascript if you use WebMessaging: <script>if(window.addEventListener){window.addEventListener("message",function(e){if(e.origin=="https://secure.signere.no"){window.location.href=e.data}},false)}else{if(window.attachEvent){window.attachEvent("onmessage",function(e){if(e.origin=="https://secure.signere.no"){window.location.href=e.data}},false)}}</script>
POST https://api.signere.no/api/ExternalLogin/AppLogin Creates a app login response witch contains the launchuri to launch the BankID app, and the requestid to get login information ans status afterwards
POST https://api.signere.no/api/ExternalLogin/BankIDMobileLogin/Create Creates a BankID mobile login response witch contains the merchantref to display to the user, and requestid for getting login result
POST https://api.signere.no/api/ExternalLogin/BankIDMobileLogin/Start Starts the BankID mobile session that where created by the BankIDMobileLogin/Create call.
PUT https://api.signere.no/api/ExternalLogin/InvalidateLogin Invalidates a login request (set the operationstatus to LOGININVALIDATED) to prevent replay attacks
DescriptionRequired/OptionalDocumentation
GET https://api.signere.no/api/externalsign/{DocumentId} Get the URLs to sign the Document.
GET https://api.signere.no/api/externalsign/ViewerUrl/{DocumentId}/{Domain}/{Language} Get the URLs to view a viewerapplet in a iFrame on your site.
GET https://api.signere.no/api/externalsign/BankIDMobileSign/Status/{SigneeRefId} Get status of the BankID mobile Sign session
POST https://api.signere.no/api/externalsign Creates a externalsign request, to integrate signing of documents in to a website. BankID error codes: CLIENT_IP_MISMATCH = 999, NOT_VALID_AUTHCOOKIE = 998 MISSING_AUTHCOOKIE = 994 MISSING_PID = 997 BANKID_INIT_TOUCHED_TWICE = 995; BANKID_VERIFY_TOUCHED_TWICE = 995 SIGNUSER_AUTHUSER_MISMATCH = 996 OLD_JAVA = 993; DISABLED_JAVA = 992; DISABLED_COOKIES = 993; SOCIALSECURITY_MISMATCH = 991 BANKIDPID_MISMATCH = 990 ITEM_NOT_FOUND = 2022
PUT https://api.signere.no/api/externalsign/BankIDAppUrl Creates a app launch uri for the BankID app (iOS and Android) for signing a document for given signeeref
PUT https://api.signere.no/api/externalsign/BankIDMobileSign Starts a BankID mobile sign session for the given document, with given mobilenumber and date of birth. Returns the BankID mobile reference "Snill bank"
DescriptionRequired/OptionalDocumentation
GET https://api.signere.no/api/Form/GetForms Gets all forms to the authenticated documentprovider
GET https://api.signere.no/api/Form/GetSignedForms?formId={formId}&fromDate={fromDate}&toDate={toDate} Gets all signed forms to the authenticated documentprovider. Can filter results by applying the imputparameters.
GET https://api.signere.no/api/Form/GetFormAttachment?formId={formId}&FormSignatureId={FormSignatureId}&AttatchmentReference={AttatchmentReference} Gets the attachements to the form.
GET https://api.signere.no/api/Form/GetSignedForm?documentid={documentid} Gets a signed form from DocumentID
GET https://api.signere.no/api/Form/GetSignedFormByFormSessionId?formId={formId}&formSessionId={formSessionId} Gets a signed form from formId and formSessionId
PUT https://api.signere.no/api/Form/EnableForm?formId={formId} Enables the form
PUT https://api.signere.no/api/Form/DisableForm?formId={formId} Disables the form
DescriptionRequired/OptionalDocumentation
GET https://api.signere.no/api/Invoice/{year}/{month} Returns a list of invoice transactions for the given month https://api.signere.no/api/Invoice/2013/12
DescriptionRequired/OptionalDocumentation
POST https://api.signere.no/api/license/{DealerId} Parses a license file and returns accountinformation to use in your app/website
DescriptionRequired/OptionalDocumentation
GET https://api.signere.no/api/Message/{MessageId} Gets details for a specific message. Remark: if using Json, a GUID must not contain dashes (-), unlike XML.
GET https://api.signere.no/api/Message/Document/{DocumentId} Retrieves a list of all the messages that are sent for the given document. Remark: if using Json, a GUID must not contain dashes (-), unlike XML.
POST https://api.signere.no/api/Message Sends a message to the signees of a given document. Returns HTTP status code "created" if the message was successfully created and distributed. Remark: if using Json, a GUID must not contain dashes (-), unlike XML.
POST https://api.signere.no/api/Message/SendExternalMessage Sends a message to an external person with a link/URL to view a document. The external person will receive an OTP code via SMS (to the given mobile number) to access the document on the issued URL.
PUT https://api.signere.no/api/Message/SendNewDocumentMessage Sends a new message to the Signeeref if the first one failed, can also be sendt to a different email address.
DescriptionRequired/OptionalDocumentation
DELETE https://api.signere.no/api/Receiver/{ProviderId}/{ReceiverId} Deletes a given receiver
DELETE https://api.signere.no/api/Receiver/{ProviderId} Deletes all the receivers for this provider
GET https://api.signere.no/api/Receiver/{ReceiverId}?ProviderId={ProviderId} Returns the given receiver
GET https://api.signere.no/api/Receiver?ProviderId={ProviderId} Returns alle the receivers registered to the provider
POST https://api.signere.no/api/Receiver Creates a receiver for this provider
POST https://api.signere.no/api/Receiver/CreateMultipleReceivers No Documentation Found.
DescriptionRequired/OptionalDocumentation
GET https://api.signere.no/api/SignereId/{RequestId}?metadata={metadata} Retrives a SignereID session to get the information aboute the authorized user
GET https://api.signere.no/api/SignereId/Completed/{RequestId} Check if a SignereID session is completed or not, used mainly for BankID mobile when the GUI is self hosted
POST https://api.signere.no/api/SignereId Creates a SignereID request, and returns a url. This url can be used in an iFrame (if the iFrame property is set) or used in a redirect. Example url: https://idtest.signere.no/NoBankIDWeb/Detector?sessionid=251952826...... To detect if user is on a mobile device check out http://detectmobilebrowsers.com/. To check for tablet add check for ipad/android or mobile in the useragent string. The login will automaticly get status LOGINTIMEDOUT 5 minutes after successfull login Use this javascript if you use WebMessaging https://signerecommon.blob.core.windows.net/files/signereid_webmessaging.js
PUT https://api.signere.no/api/SignereId/Invalidate Invalidates a SignereID request (set the operationstatus to LOGININVALIDATED) to prevent replay attacks
DescriptionRequired/OptionalDocumentation
GET https://api.signere.no/api/Statistics?Year={Year}&Month={Month}&Day={Day}&Status={Status} Returns a statistics response object with various information.
DescriptionRequired/OptionalDocumentation
GET https://api.signere.no/api/Status/ServerTime Returns the UTC time of the server
GET https://api.signere.no/api/Status/Ping/{request} Send in a Unique string and check if you get the same one in return, this checks that the service is operativ. It requires the HTTP header: PingToken and a ping token (this you can get from Signere.no support) this to limit access to this feature.

REST HTTP headers

All REST resources in this API demand that the HTTP request contains certain headers. The relevant headers are listed below. In the description of each header, it is indicated whether it is required or optional. There is also a description of the expected format of each header and an example of a valid header.

Header: API-ID

DescriptionRequired/OptionalExample
This is the unique identification for the document provider's API account. The ID is necessary in order for signere.no to authenticate the request. Required API-ID: 2d0193b6-5dcb-4f74-b6da-a0b500dc18d0

Header: API-TOKEN

DescriptionRequired/OptionalExample
The API-TOKEN header should contain a hash where one uses one of the two account keys and some other parameters depending on the request type (see the API security tab for an explanation of the token generation algorithm). Since the account keys are secret, it is very important that they are not passed directly in the header. Required API-TOKEN: FD714617939D4BB01C47BD959EEF911B1BC53...

Header: API-TIMESTAMP

DescriptionRequired/OptionalExample
This is the timestamp for when the request was sent. The server checks the timestamp, and denies access to the resources if the request timestamp deviates more than 5 minutes from server time. The header timestamp should be the time in UTC, complying with the ISO8601 formatting standard. The timestamp should be the same as the one used to generate the API token. Required API-TIMESTAMP: 2012-09-21T12:40:26
DescriptionRequired/OptionalExample
This header indicates whether one is using the primary or secondary key in the API-TOKEN. By default, the server assumes that the primary key is used, and tries to match the hash with the hashed primary key. Therefore, this header must be included and set to true if the secondary key is used instead. Optional API-USINGSECONDARYTOKEN: false

Header: API-ALGORITHM

DescriptionRequired/OptionalExample
This header specifies which encryption algorithm that was used to generate the API-TOKEN header. By default, the server assumes that one is using a 256 bit HMAC SHA encryption (SHA256). If one uses another algorithm, this must be specified here. Optional API-ALGORITHM: SHA512
DescriptionRequired/OptionalExample
In some cases it can be convenient to receive error messages from the server in the headers instead of the body. This could be the case if one catches a web exception and does not have access to the response body. If this header is set to true, a string with all error messages will be returned in the response headers. Optional API-RETURNERRORHEADER: true

API security

The security of the API lies in the communication between client and server, and authentication of requests on the server. All communication between the client and the REST server is transported using the HTTPS protocol, which prevents eavesdropping and man-in-middle attacks.

Furthermore, the API uses a set of private keys to authenticate users. For each API account, Signere.no issues two keys and one ID. The ID identifies the account itself, but does not give access without authentication. The primary key gives access to all resources that are available in the API, whereas the secondary key only gives access to day-to-day services. These keys are secret to the public. From the keys, the contents, timestamp and HTTP verb, one must generate a hashed token which is passed as a header in the HTTP request. The server will know which key that belongs to the client’s user account based on the API ID. To authenticate the request, the server will re-generate the token and compare it with the received one to authenticate the client.

The token generation algorithm is based on the SHA256 or SHA512 cryptographic hash functions. For GET requests, the API-TOKEN should be a hash of the resource URL and the timestamp that is passed in API-TIMESTAMP, and either the primary or secondary account key should be used as key for the encryption algorithm. The string that should be hashed is on the form "URL&Timestamp=API-TIMESTAMP&Httpverb=HTTPVERB", where URL is the request URL, API-TIMESTAMP is the passed timestamp and HTTPVERB is the HTTP verb being used, written in uppercase (either GET or DELETE).

For POST and PUT requests, the entire message body (JSON or XML string) should be hashed together with the timestamp. The string that is hashed should be on the form MESSAGE_JSON_STRING{Timestamp:"API-TIMESTAMP",Httpverb:"POST/PUT"} for JSON contents, where MESSAGE_JSON_STRING is the message body in the request (including curly brackets) and API-TIMESTAMP is the passed timestamp. For XML contents it should be on the form MESSAGE_XML_STRING<Timestamp>API-TIMESTAMP</Timestamp><Httpverb>POST/PUT</Httpverb>, where MESSAGE_XML_STRING is the message body (including angle brackets).

Note that the string in the JSON case includes quotes around the timestamp and the HTTP verb, whereas the string in the XML case does not.

For clarity, the token generation routines are given in pseudocode below. Quotes inside a string are escaped with “\"”, and the hash is computed with the HMAC SHA512 algorithm.

function GenerateApiToken_GET_DELETE(url, accountKey, timestamp) {

      declare variable urlWithTimeStamp;

      set urlWithTimeStamp to url +“&Timestamp=” +timestamp” +”&Httpverb=GET/DELETE”; 

      return GetSHA512(urlWithTimeStamp, secretKey)

}

function GenerateToken_POST_PUT_JSON(jsonString, accountKey, timestamp) {

      declare variable jsonWithTimeStampAndHttpverb; 

      set jsonWithTimeStampAndHttpverb to jsonString+”{Timestamp:” + “\”” + timestamp + “\”,Httpverb:\”POST/PUT\”” + “}”;

      return GetSHA512(jsonWithTimeStampAndHttpverb, accountKey);

}

function GenerateToken_POST_PUT_XML(xmlString, accountKey, timestamp) {

      declare variable xmlWithTimeStampAndHttpverb;

      set xmlWithTimeStamp to xmlString+ “<Timestamp>” + timestamp + “</Timestamp>”+”<Httpverb>”+”POST/PUT”+”</Httpverb>”;

      return GetSHA512(xmlWithTimeStampAndHttpverb, accountKey);

}

function GetSHA512(text, accountKey) {

      use accountKey as key in HMAC SHA512 algorithm;

      compute SHA512Hash from text;

      return SHA512Hash;

}

API terms and keywords

In the world of Signere.no, a number of special terms are used. In the following we present the most common terms and keywords used in the API and give an explanation of their applications in for instance the API data model.

API ID: A unique identifier (GUID) for a Signere.no user account.

API key: A private key that is used to authenticate requests to Signere.no through the API. An API key should never be shared outside of the organization that owns the user account.

Document provider: A document provider is any organization or person registered as a user on Signere.no. The term is sometimes used loosely about the user that uploads documents, but in principle it refers to the organization/person that owns a user account at Signere.no. To each document provider, there is associated an API ID and two API keys.

Document job: A document job is an abstraction of the process of issuing documents belonging together, and is used as a data model object in the API. To exemplify, think about a Signere.no user working with a specific customer, requiring the customer to sign a set of documents in order to settle an agreement. For the specific process and the given customer, these documents logically belong together. By assigning the documents to the same document job, all documents are linked to the same contact person with the document provider.

Document file: A document file is, as the name suggests, the very data file of a document. In the context of the Signere.no client library, it is an object which also contains some metadata about the data file, like the name of the file, the document ID and the date of creation. In the context of the API resource DocumentFile, it is the object returned when the user requests either a signed or unsigned document.

SigneeRef: In the API, a SigneeRef models a person who is supposed to sign a document. It includes parameters like the name, e-mail address etc. In contrast to a Signee, the identity of a SigneeRef is not necessarily verified. For instance, when creating a document for signature, the SigneeRefs listed in the request are the persons that are supposed to sign the document, but when they have signed, they become Signees in the API model.

Signee: A signee is a person who has signed a document, and where the identity is verified with BankID. A Signee object has a one-to-one correspondence with a particular signature. The time of signature and the BankID PID (personal identifier) used in the signature are contained in it.

Receiver: A receiver is a person or organization to which one intends to issue documents more than once. By creating a receiver through the API (or in the Signere.no portal), one can store and retrieve information about returning customers instead of having to type the information every time a document is to be issued.

External signature: It is possible to perform the process of signature on your own site instead of letting the signee use the Signere.no portal, which in our terminology is called an external signature. To do so, one can make a request to the resource ExternalSign and integrate the process into an <iframe> (see the resource documentation for more details). 

External login: Just as with signatures, it is possible to integrate BankID on your own site through the Signere.no API and let your users log in to your services by means of the BankID authentication. We call this an external login. To do so, one can make a request to the resource ExternalLogin and integrate the process into an <iframe> (see the resource documentation for more details). 

FromURI: In the API documentation, for each method the parameters in the request are listed, and at the end it is indicated whether the parameter is passed in the URI or in the body. FromURI indicates that the parameter is read from the URI.

FromBody: In the API documentation, for each method the parameters in the request are listed, and at the end it is indicated whether the parameter is passed in the URI or in the body. FromBody indicates that the parameter is read from the body of the HTTP request.

Client code examples

We present an example of a basic console application written in C# that uses the Signere.no .NET client library.

The program uploads a document to the server, which notifies the signee that he/she has received a new document. Then, the program downloads the signed document (assuming that the document has been signed).


using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Unipluss.Sign.Client.Models;
using Unipluss.Sign.ExternalContract.Entities;
namespace SignereClientConsoleDemo
{
class Program
{
private const string url = "https://api.signere.no";
private const string apiId = "eb09fc43f16c44e9b9a4a149009834c9";
//Can be obtained from "min side"
private const string primaryKey = "bjRXV2RrYmNWUHNKRXR1T1J5ZXpRZz09LGxOaTU0VlFNeGVGTEZ
iMzNNZmxWNnhpWGxwS2ZNcWRlVE1DekEvQWMwSDg9";
//Can be obtained from "min side"
private const string filePath = @@"C:\signeredemo.pdf";
private const string filePathSigned = @@"C:\signeredemo.sdo";
static void Main(string[] args){
var client = new Unipluss.Sign.Client.Client(url, apiId, true, true);
Console.WriteLine("Sending data");
Document result = client.CreateSingleDocument(CreateDocument(), filePath,
primaryKey);
Console.WriteLine("Data received from server");
Console.WriteLine(SerializeObjectToString(result));
Console.WriteLine("Click when the document is signed");
Console.ReadLine();
Document signedDocument = client.GetDocument(result.Id, primaryKey);
var receiver = signedDocument.SigneeRefs.FirstOrDefault();
Console.WriteLine("Signed {0}, by: {1} date of birth: {2}",
signedDocument.LastSignature,receiver.SignName,
receiver.DateOfBirth);
client.DownloadSignedDocument(result.Id, filePathSigned, primaryKey);
Console.ReadLine();
}
//Provide your own test data
private static NewSingleDocument CreateDocument() {
var mottaker = new SigneeRef()
{
FirstName = "Ola",
LastName = "Normann",
CompanyName = "Normann AS",
Email = "ola@normann.no",
ExternalSigneeId = "100500",
Mobile = "+4744332211",
SocialSecurityNumber = "07128312345",
OrgNo = "987654321"
};
var doc = new NewSingleDocument()
{
Contact_Email = "testman@test.no",
Contact_Mobile = "+4799887766",
Contact_Name = "John Doe",
Contact_Phone = "+4755443322",
Contact_Url = "http://www.signere.no",
CreatedByApplication = "Demo console app",
Description = "Test document from console",
ExternalDocumentId = "demo ref",
Language = NewSingleDocument.Languages.EN,
MessageEmail = "Hello! Please click this link to sign: {signlink}",
Title = "Title of demo document " + DateTime.Now.ToString(),
TopicEmail = "E-mail topic",
SigneeRefs = new List<SigneeRef>(),
};
doc.SigneeRefs.Add(mottaker);
return doc;
}
public static string SerializeObjectToString<T>(T T_object) {
var flags = BindingFlags.Instance | BindingFlags.Public |
BindingFlags.FlattenHierarchy;
PropertyInfo[] infos = T_object.GetType().GetProperties(flags);
StringBuilder sb = new StringBuilder();
string typeName = T_object.GetType().Name;
sb.AppendLine(typeName);
sb.AppendLine(String.Empty.PadRight(typeName.Length + 5, '='));
foreach (var info in infos) {
object value = info.GetValue(T_object, null);
sb.AppendFormat("{0}: {1}{2}", info.Name, value != null ? value : "null",
Environment.NewLine);
}
return sb.ToString();
}
}
}