projects/wms-framework/src/lib/wcfserviceinvocationsupport/HttpChannel.ts
Base class for communication channels
Properties |
|
Methods |
|
constructor(client: ClientBase<T>)
|
||||||||
Constructor
Parameters :
|
RemoteAddress |
Type : EndpointAddress
|
Service Endpoint address |
Public requestHeaders |
Type : HttpHeaders
|
Default value : null
|
Suffix added to the URL when performing request. This suffix is defined in the specific endpoint for JSON services |
Private serializerFactory |
Default value : new SerializerFactory()
|
The serializer factory for special primitives types serialization. |
Via |
Type : Uri
|
Service Uri |
DefaultSendTimeout |
Type : TimeRange
|
Default value : new TimeRange()
|
Inherited from
WcfChannelBase
|
Defined in
WcfChannelBase:389
|
Public HttpClient |
Type : HttpClient
|
Default value : null
|
Inherited from
WcfChannelBase
|
Defined in
WcfChannelBase:380
|
Optional angular HttpClient instance to use with this object |
Protected UsePost |
Default value : true
|
Inherited from
WcfChannelBase
|
Defined in
WcfChannelBase:388
|
Flag to determine if this channel is going to perform the requests using POST or GET |
Abort |
Abort()
|
Inherited from
WcfCommunicationObject
|
Defined in
WcfCommunicationObject:108
|
Returns :
void
|
BeginClose | |||||||||
BeginClose(callback: AsyncCallback, asyncState: any)
|
|||||||||
Inherited from
WcfCommunicationObject
|
|||||||||
Defined in
WcfCommunicationObject:116
|
|||||||||
Parameters :
Returns :
IAsyncResult
|
BeginCloseWithTimeout | ||||||||||||
BeginCloseWithTimeout(timeout: TimeRange, callback: AsyncCallback, asyncState: any)
|
||||||||||||
Inherited from
WcfCommunicationObject
|
||||||||||||
Defined in
WcfCommunicationObject:119
|
||||||||||||
Parameters :
Returns :
IAsyncResult
|
Private BeginInvoke | ||||||||||||||||
BeginInvoke(message: Message, callback: AsyncCallback, asyncState: any)
|
||||||||||||||||
Initiates the request for the given service method
Parameters :
Returns :
IAsyncResult
{IAsyncResult} the result |
BeginOpen | |||||||||
BeginOpen(callback: AsyncCallback, asyncState: any)
|
|||||||||
Inherited from
WcfCommunicationObject
|
|||||||||
Defined in
WcfCommunicationObject:129
|
|||||||||
Parameters :
Returns :
IAsyncResult
|
BeginOpenWithTimeout | ||||||||||||
BeginOpenWithTimeout(timeout: TimeRange, callback: AsyncCallback, asyncState: any)
|
||||||||||||
Inherited from
WcfCommunicationObject
|
||||||||||||
Defined in
WcfCommunicationObject:132
|
||||||||||||
Parameters :
Returns :
IAsyncResult
|
BeginRequest | ||||||||||||
BeginRequest(message: Message, callback: AsyncCallback, state: any)
|
||||||||||||
Inherited from
WcfChannelBase
|
||||||||||||
Defined in
WcfChannelBase:92
|
||||||||||||
Parameters :
Returns :
any
|
BeginRequestWithTimeout | |||||||||||||||
BeginRequestWithTimeout(message: Message, timeout: TimeRange, callback: AsyncCallback, state: any)
|
|||||||||||||||
Inherited from
WcfChannelBase
|
|||||||||||||||
Defined in
WcfChannelBase:97
|
|||||||||||||||
Parameters :
Returns :
any
|
CloseWithTimeout | ||||||
CloseWithTimeout(timeout: TimeRange)
|
||||||
Inherited from
WcfCommunicationObject
|
||||||
Defined in
WcfCommunicationObject:142
|
||||||
Parameters :
Returns :
void
|
EndClose | ||||||
EndClose(result: IAsyncResult)
|
||||||
Inherited from
WcfCommunicationObject
|
||||||
Defined in
WcfCommunicationObject:111
|
||||||
Parameters :
Returns :
any
|
EndClose | ||||||
EndClose(result: IAsyncResult)
|
||||||
Parameters :
Returns :
any
|
EndClose | ||||||
EndClose(result: any)
|
||||||
Parameters :
Returns :
void
|
Private EndInvoke | |||||||||
EndInvoke(result: IAsyncResult, classConstructor?: any)
|
|||||||||
Parameters :
Returns :
any
|
EndOpen | ||||||
EndOpen(result: IAsyncResult)
|
||||||
Inherited from
WcfCommunicationObject
|
||||||
Defined in
WcfCommunicationObject:126
|
||||||
Parameters :
Returns :
void
|
EndRequest | ||||||
EndRequest(result: IAsyncResult)
|
||||||
Inherited from
WcfChannelBase
|
||||||
Defined in
WcfChannelBase:105
|
||||||
Parameters :
Returns :
any
|
Private generateFaultException | ||||||
generateFaultException(ex: any)
|
||||||
Parameters :
Returns :
any
|
getErrorMessageFromResponse | ||||||||
getErrorMessageFromResponse(e: unknown)
|
||||||||
Gets the error from the response
Parameters :
Returns :
any
the error message or the FaultException object |
Private getHttpClient |
getHttpClient()
|
Gets the http client
Returns :
HttpClient
the HttpClient object |
Private getXmlNode | |||||||||
getXmlNode(root: Element, path: string[])
|
|||||||||
Parameters :
Returns :
any
|
Protected OnBeginClose | ||||||||||||
OnBeginClose(timeout: any, callback: AsyncCallback, state: object)
|
||||||||||||
Inherited from
WcfCommunicationObject
|
||||||||||||
Defined in
WcfCommunicationObject:195
|
||||||||||||
Parameters :
Returns :
IAsyncResult
|
Protected OnBeginOpen | ||||||||||||
OnBeginOpen(timeout: any, callback: AsyncCallback, state: object)
|
||||||||||||
Inherited from
WcfCommunicationObject
|
||||||||||||
Defined in
WcfCommunicationObject:202
|
||||||||||||
Parameters :
Returns :
IAsyncResult
|
OpenWithTimeout | ||||||
OpenWithTimeout(timeout: TimeRange)
|
||||||
Inherited from
WcfCommunicationObject
|
||||||
Defined in
WcfCommunicationObject:139
|
||||||
Parameters :
Returns :
void
|
Private requestUsingGet | ||||||||||||||||
requestUsingGet(message: Message, callback: AsyncCallback, asyncState: any)
|
||||||||||||||||
Does the request for the given service method
Parameters :
Returns :
IAsyncResult
{IAsyncResult} the result |
Private requestUsingPost | ||||||||||||||||
requestUsingPost(message: Message, callback: AsyncCallback, asyncState: any)
|
||||||||||||||||
Does the request for the given service method
Parameters :
Returns :
IAsyncResult
{IAsyncResult} the result |
SetHeaders | ||||||||
SetHeaders(message: Message)
|
||||||||
Appends the headers to the request headers.
Parameters :
Returns :
void
|
GetProperty |
GetProperty()
|
Inherited from
WcfChannelBase
|
Defined in
WcfChannelBase:449
|
Type parameters :
|
Returns the typed object requested, if present, from the appropriate layer in the channel stack.
Returns :
T
{T} |
Close |
Close()
|
Inherited from
WcfCommunicationObject
|
Defined in
WcfCommunicationObject:321
|
Causes a communication object to transition from its current state into the closed state.
Returns :
void
|
Open |
Open()
|
Inherited from
WcfCommunicationObject
|
Defined in
WcfCommunicationObject:299
|
Causes a communication object to transition from the created state into the opened state.
Returns :
void
|
import { IAsyncResult, AsyncCallback } from './AsyncResultSupport';
import { InvokeAsyncCompletedEventArgs } from './InvokeAsyncCompletedEventArgs';
import { Application } from '../basecomponentmodel/Application';
import { catchError } from 'rxjs/operators';
import { ClientBase } from './ClientBase';
import {
deserializeErrorDetail,
Exception,
FaultException,
getTargetType,
serializeObjectAsJson,
smGetExceptionInstance,
TimeRange,
Uri,
} from '../baseframework';
import {
HttpClient,
HttpErrorResponse,
HttpHeaders,
} from '@angular/common/http';
import { IRequestChannel } from './IRequestChannel';
import { WcfChannelBase } from './CommunicationSupport';
import { SerializerFactory } from '../baseframework/TypeSerializers/SerializerFactory';
import { EndpointAddress } from './EndpointAddress';
import { Message } from './Message';
import { SoapAsyncResult } from './soapAsyncResult';
/**
* Base class for communication channels
*
* @export
* @class HttpChannel
* @template T
*/
export class HttpChannel<T> extends WcfChannelBase implements IRequestChannel {
/**
* Service Uri
*
* @memberof IRequestChannel
*/
Via: Uri;
/**
* Service Endpoint address
*
* @memberof IRequestChannel
*/
RemoteAddress: EndpointAddress;
/**
* The serializer factory for special primitives types serialization.
*
* @private
* @memberof HttpChannel
*/
private serializerFactory = new SerializerFactory();
/**
* Suffix added to the URL when performing request. This suffix is defined in the specific endpoint for JSON services
*
* @memberof HttpChannel
*/
public requestHeaders: HttpHeaders = null;
/**
* Constructor
*
* @param {ClientBase} client the client base to set to the HttpChannel
* @memberof HttpChannel
*/
constructor(private client: ClientBase<T>) {
super(null);
this.client = client;
this.HttpClient = this.client.HttpClientToUse;
}
BeginRequest(message: Message, callback: AsyncCallback, state: any) {
this.SetHeaders(message);
this.UsePost = message.UsePost;
return this.BeginInvoke(message, callback, state);
}
BeginRequestWithTimeout(
message: Message,
timeout: TimeRange,
callback: AsyncCallback,
state: any
) {
return this.BeginRequest(message, callback, state);
}
EndRequest(result: IAsyncResult) {
return this.EndInvoke(result, result.classConstructor);
}
Abort() {
throw new Error('Method not implemented.');
}
EndClose(result: IAsyncResult);
EndClose(result: IAsyncResult);
EndClose(result: any) {
throw new Error('Method not implemented.');
}
BeginClose(callback: AsyncCallback, asyncState: any): IAsyncResult {
throw new Error('Method not implemented.');
}
BeginCloseWithTimeout(
timeout: TimeRange,
callback: AsyncCallback,
asyncState: any
): IAsyncResult {
throw new Error('Method not implemented.');
}
EndOpen(result: IAsyncResult) {
throw new Error('Method not implemented.');
}
BeginOpen(callback: AsyncCallback, asyncState: any): IAsyncResult {
throw new Error('Method not implemented.');
}
BeginOpenWithTimeout(
timeout: TimeRange,
callback: AsyncCallback,
asyncState: any
): IAsyncResult {
throw new Error('Method not implemented.');
}
OpenWithTimeout(timeout: TimeRange): void {
throw new Error('Method not implemented.');
}
CloseWithTimeout(timeout: TimeRange): void {
throw new Error('Method not implemented.');
}
/**
* Appends the headers to the request headers.
*
* @param {Message} message Message object that continas the custom headers
* @memberof HttpChannel
*/
SetHeaders(message: Message) {
if (message.Headers.count > 0) {
this.requestHeaders = new HttpHeaders();
for (let keyPair of message.Headers) {
let requestValue: any =
typeof keyPair.Message === 'string' ||
keyPair.Message instanceof String
? keyPair.Message
: serializeObjectAsJson(keyPair.Message);
this.requestHeaders = this.requestHeaders.append(
keyPair.MessageKey,
requestValue
);
}
}
}
private EndInvoke(result: IAsyncResult, classConstructor?: any): any {
return this.client.binding.CreateResponseMessage(result, classConstructor);
}
/**
* Initiates the request for the given service method
*
* @param {string} methodName name of the service method to call
* @param {any[]} requestArgs either a collection like [{name: any, value: any}] or [any] to use for method arguments
* @param {AsyncCallback} callback request callback
* @param {*} asyncState asycn state
* @return {*} {IAsyncResult} the result
* @memberof HttpChannel
*/
private BeginInvoke(
message: Message,
callback: AsyncCallback,
asyncState: any
): IAsyncResult {
if (this.UsePost) {
return this.requestUsingPost(message, callback, asyncState);
} else {
return this.requestUsingGet(message, callback, asyncState);
}
}
protected OnBeginClose(
timeout: any,
callback: AsyncCallback,
state: object
): IAsyncResult {
throw new Error('Method not implemented.');
}
protected OnBeginOpen(
timeout: any,
callback: AsyncCallback,
state: object
): IAsyncResult {
throw new Error('Method not implemented.');
}
/**
* Does the request for the given service method
*
* @param {string} methodName name of the service method to call
* @param {any[]} requestArgs either a collection like [{name: any, value: any}] or [any] to use for method arguments
* @param {AsyncCallback} callback request callback
* @param {*} asyncState asycn state
* @return {*} {IAsyncResult} the result
* @memberof HttpChannel
*/
private requestUsingGet(
message: Message,
callback: AsyncCallback,
asyncState: any
): IAsyncResult {
const localResult = {
AsyncState: null,
IsCompleted: false,
callback: (x) => {},
};
const request = this.getHttpClient()
.get(message.buildUrl(), { headers: this.requestHeaders })
.pipe(
catchError((e, y) => {
console.error(e);
try {
if (localResult.callback) {
var exception = new Exception(e.message, e.statusText);
const invokeAsyncCompletedEventArgs =
new InvokeAsyncCompletedEventArgs(null, exception, false, null);
localResult.callback(invokeAsyncCompletedEventArgs);
}
} catch (e) {
//Mobilize-TODO: Second parameter type should be: ApplicationUnhandledExceptionEventArgs
Application?.Current?.UnhandledException?.fire([
this,
{
ExceptionObject: smGetExceptionInstance(e),
Handled: false,
},
]);
}
return [];
})
)
.subscribe((result) => {
const endOperationResult = callback({
AsyncState: { message: message, d: result },
IsCompleted: true,
});
if (localResult.callback) {
var results = endOperationResult as any;
const invokeAsyncCompletedEventArgs =
new InvokeAsyncCompletedEventArgs(results, null, false, null);
localResult.callback(invokeAsyncCompletedEventArgs);
}
});
return localResult;
}
/**
* Does the request for the given service method
*
* @param {string} methodName name of the service method to call
* @param {any[]} requestArgs either a collection like [{name: any, value: any}] or [any] to use for method arguments
* @param {AsyncCallback} callback request callback
* @param {*} asyncState asycn state
* @return {*} {IAsyncResult} the result
* @memberof HttpChannel
*/
private requestUsingPost(
message: Message,
callback: AsyncCallback,
asyncState: any
): IAsyncResult {
const localResult = {
AsyncState: asyncState,
IsCompleted: false,
callback: (x) => {},
};
this.getHttpClient()
.post(message.buildUrl(), message.buildBody(), {
headers: this.requestHeaders,
responseType: message.responseType as any,
})
.pipe(
catchError((e, y) => {
console.error(e);
try {
/* istanbul ignore else */
if (localResult.callback) {
let exception = this.getErrorMessageFromResponse(e);
if (typeof exception === 'string') {
exception = new Exception(
this.getErrorMessageFromResponse(e),
e.statusText
);
}
const invokeAsyncCompletedEventArgs =
new InvokeAsyncCompletedEventArgs(
null,
exception,
false,
localResult.AsyncState
);
localResult.callback(invokeAsyncCompletedEventArgs);
}
} catch (e) {
//Mobilize-TODO: Second parameter type should be: ApplicationUnhandledExceptionEventArgs
Application?.Current?.UnhandledException?.fire([
this,
{
ExceptionObject: smGetExceptionInstance(e),
Handled: false,
},
]);
}
return [];
})
)
.subscribe((result) => {
let operationResult: IAsyncResult = message.buildPostResult(
asyncState,
result
);
const endOperationResult = callback(operationResult);
/* istanbul ignore else */
if (localResult.callback) {
var results = endOperationResult as any;
const invokeAsyncCompletedEventArgs =
new InvokeAsyncCompletedEventArgs(
results,
null,
false,
localResult.AsyncState
);
localResult.callback(invokeAsyncCompletedEventArgs);
}
});
return localResult;
}
/**
* Gets the error from the response
* @param e error
* @returns the error message or the FaultException object
*/
getErrorMessageFromResponse(e: unknown): any {
if (
e instanceof HttpErrorResponse &&
typeof e.error === 'string' &&
e.error.startsWith('<Fault ')
) {
const contentType = e.headers.get('content-type');
if (
typeof contentType === 'string' &&
contentType.indexOf('application/xml') !== -1
) {
const parser = new DOMParser();
const tree = parser.parseFromString(e.error, 'application/xml');
const errorMessageNode = this.getXmlNode(tree.documentElement, [
'Reason',
'Text',
]);
if (errorMessageNode?.hasChildNodes()) {
return errorMessageNode.childNodes[0].nodeValue;
}
}
}
let ex = e as any;
if (ex.error?.Type && ex.error?.Type === 'FaultException') {
return this.generateFaultException(ex);
}
if (ex.error && typeof ex.error?.Message === 'string') {
return ex.error.Message;
}
return ex.message;
}
private generateFaultException(ex: any): any {
let exception = new FaultException();
if (ex.error.DetailType) {
let detailTargetType = getTargetType(ex.error.DetailType);
if (detailTargetType) {
exception.Detail = deserializeErrorDetail(
ex.error.Detail,
detailTargetType
);
}
}
return exception;
}
private getXmlNode(root: Element, path: string[]) {
let tmpRoot = root;
for (const pathFragment of path) {
let found = false;
// eslint-disable-next-line @typescript-eslint/prefer-for-of
for (let j = 0; j < tmpRoot.children.length; j++) {
if (tmpRoot.children[j].nodeName === pathFragment) {
tmpRoot = tmpRoot.children[j];
found = true;
break;
}
}
if (!found) {
return null;
}
}
return tmpRoot;
}
/**
* Gets the http client
*
* @return {HttpClient} the HttpClient object
* @memberof HttpChannel
*/
private getHttpClient(): HttpClient {
if (this.HttpClient) {
return this.HttpClient;
} else if (Application.Current?.angularHttpClient) {
return Application.Current?.angularHttpClient;
} else {
throw new Error('FATAL cannot find HTTPClient to perform request');
}
}
}