File

projects/wms-framework/src/lib/wcfserviceinvocationsupport/HttpChannel.ts

Description

Base class for communication channels

Extends

WcfChannelBase

Implements

IRequestChannel

Index

Properties
Methods

Constructor

constructor(client: ClientBase<T>)

Constructor

Parameters :
Name Type Optional Description
client ClientBase<T> No

the client base to set to the HttpChannel

Properties

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

Methods

Abort
Abort()
Inherited from WcfCommunicationObject
Returns : void
BeginClose
BeginClose(callback: AsyncCallback, asyncState: any)
Inherited from WcfCommunicationObject
Parameters :
Name Type Optional
callback AsyncCallback No
asyncState any No
Returns : IAsyncResult
BeginCloseWithTimeout
BeginCloseWithTimeout(timeout: TimeRange, callback: AsyncCallback, asyncState: any)
Inherited from WcfCommunicationObject
Parameters :
Name Type Optional
timeout TimeRange No
callback AsyncCallback No
asyncState any No
Returns : IAsyncResult
Private BeginInvoke
BeginInvoke(message: Message, callback: AsyncCallback, asyncState: any)

Initiates the request for the given service method

Parameters :
Name Type Optional Description
message Message No
callback AsyncCallback No

request callback

asyncState any No

asycn state

Returns : IAsyncResult

{IAsyncResult} the result

BeginOpen
BeginOpen(callback: AsyncCallback, asyncState: any)
Inherited from WcfCommunicationObject
Parameters :
Name Type Optional
callback AsyncCallback No
asyncState any No
Returns : IAsyncResult
BeginOpenWithTimeout
BeginOpenWithTimeout(timeout: TimeRange, callback: AsyncCallback, asyncState: any)
Inherited from WcfCommunicationObject
Parameters :
Name Type Optional
timeout TimeRange No
callback AsyncCallback No
asyncState any No
Returns : IAsyncResult
BeginRequest
BeginRequest(message: Message, callback: AsyncCallback, state: any)
Inherited from WcfChannelBase
Defined in WcfChannelBase:92
Parameters :
Name Type Optional
message Message No
callback AsyncCallback No
state any No
Returns : any
BeginRequestWithTimeout
BeginRequestWithTimeout(message: Message, timeout: TimeRange, callback: AsyncCallback, state: any)
Inherited from WcfChannelBase
Defined in WcfChannelBase:97
Parameters :
Name Type Optional
message Message No
timeout TimeRange No
callback AsyncCallback No
state any No
Returns : any
CloseWithTimeout
CloseWithTimeout(timeout: TimeRange)
Inherited from WcfCommunicationObject
Parameters :
Name Type Optional
timeout TimeRange No
Returns : void
EndClose
EndClose(result: IAsyncResult)
Inherited from WcfCommunicationObject
Parameters :
Name Type Optional
result IAsyncResult No
Returns : any
EndClose
EndClose(result: IAsyncResult)
Parameters :
Name Type Optional
result IAsyncResult No
Returns : any
EndClose
EndClose(result: any)
Parameters :
Name Type Optional
result any No
Returns : void
Private EndInvoke
EndInvoke(result: IAsyncResult, classConstructor?: any)
Parameters :
Name Type Optional
result IAsyncResult No
classConstructor any Yes
Returns : any
EndOpen
EndOpen(result: IAsyncResult)
Inherited from WcfCommunicationObject
Parameters :
Name Type Optional
result IAsyncResult No
Returns : void
EndRequest
EndRequest(result: IAsyncResult)
Inherited from WcfChannelBase
Defined in WcfChannelBase:105
Parameters :
Name Type Optional
result IAsyncResult No
Returns : any
Private generateFaultException
generateFaultException(ex: any)
Parameters :
Name Type Optional
ex any No
Returns : any
getErrorMessageFromResponse
getErrorMessageFromResponse(e: unknown)

Gets the error from the response

Parameters :
Name Type Optional Description
e unknown No

error

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 :
Name Type Optional
root Element No
path string[] No
Returns : any
Protected OnBeginClose
OnBeginClose(timeout: any, callback: AsyncCallback, state: object)
Inherited from WcfCommunicationObject
Parameters :
Name Type Optional
timeout any No
callback AsyncCallback No
state object No
Returns : IAsyncResult
Protected OnBeginOpen
OnBeginOpen(timeout: any, callback: AsyncCallback, state: object)
Inherited from WcfCommunicationObject
Parameters :
Name Type Optional
timeout any No
callback AsyncCallback No
state object No
Returns : IAsyncResult
OpenWithTimeout
OpenWithTimeout(timeout: TimeRange)
Inherited from WcfCommunicationObject
Parameters :
Name Type Optional
timeout TimeRange No
Returns : void
Private requestUsingGet
requestUsingGet(message: Message, callback: AsyncCallback, asyncState: any)

Does the request for the given service method

Parameters :
Name Type Optional Description
message Message No
callback AsyncCallback No

request callback

asyncState any No

asycn state

Returns : IAsyncResult

{IAsyncResult} the result

Private requestUsingPost
requestUsingPost(message: Message, callback: AsyncCallback, asyncState: any)

Does the request for the given service method

Parameters :
Name Type Optional Description
message Message No
callback AsyncCallback No

request callback

asyncState any No

asycn state

Returns : IAsyncResult

{IAsyncResult} the result

SetHeaders
SetHeaders(message: Message)

Appends the headers to the request headers.

Parameters :
Name Type Optional Description
message Message No

Message object that continas the custom headers

Returns : void
GetProperty
GetProperty()
Inherited from WcfChannelBase
Defined in WcfChannelBase:449
Type parameters :
  • T

Returns the typed object requested, if present, from the appropriate layer in the channel stack.

Returns : T

{T}

Close
Close()
Inherited from WcfCommunicationObject

Causes a communication object to transition from its current state into the closed state.

Returns : void
Open
Open()
Inherited from WcfCommunicationObject

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');
    }
  }
}

result-matching ""

    No results matching ""