constructor()

in powershell/llcsharp/operation/method.ts [95:338]


  constructor(public parent: Class, public operation: Operation, public viaIdentity: boolean, protected state: State, public viaJson: boolean = false, withResult?: boolean, objectInitializer?: DeepPartial<OperationMethod>) {
    super(
      viaJson
        ? `${operation.language.csharp?.name}ViaJsonString${withResult ? 'WithResult' : ''}`
        : viaIdentity
          ? `${operation.language.csharp?.name}ViaIdentity${withResult ? 'WithResult' : ''}`
          : `${operation.language.csharp?.name}${withResult ? 'WithResult' : ''}` || '',
      withResult ? System.Threading.Tasks.Task(ResolveResponseType(undefined, operation, state)) : System.Threading.Tasks.Task()
    );
    this.apply(objectInitializer);
    this.async = Modifier.Async;
    this.returnsDescription = `A <see cref="${withResult ? System.Threading.Tasks.Task(ResolveResponseType(undefined, operation, state)) : System.Threading.Tasks.Task()}" /> that will be complete when handling of the response is completed.`;
    const $this = this;

    this.callName = `${operation.language.csharp?.name}${withResult ? 'WithResult' : ''}_Call`;
    this.push(Using('NoSynchronizationContext', ''));

    // add parameters
    this.methodParameters = [];

    const identity = new Parameter('viaIdentity', System.String);
    if (this.viaIdentity) {
      this.addParameter(identity);
    }
    let baseUrl = '';
    const paths = [];
    const headers = [];
    const queries = [];
    const others = [];
    for (let index = 0; index < length(this.operation.parameters) && this.operation.parameters; index++) {
      const value = this.operation.parameters[index];

      if (value.language.default.name === '$host') {
        baseUrl = value.clientDefaultValue;
        continue;
      }
      const p = new OperationParameter(this, value, this.state.path('parameters', index));

      if (value.language.csharp?.constantValue) {
        const constTd = state.project.modelsNamespace.NewResolveTypeDeclaration(value.schema, true, state);
        p.defaultInitializer = constTd.deserializeFromString(KnownMediaType.UriParameter, new StringExpression(`${value.language.csharp.constantValue}`), toExpression(constTd.defaultOfType));
      }

      // don't add path parameters  when we're in identity mode
      if (!this.viaIdentity || value.protocol.http?.in !== ParameterLocation.Path) {
        switch (value.protocol.http?.in) {
          case ParameterLocation.Path:
            paths.push(p);
            break;
          case ParameterLocation.Header:
            headers.push(p);
            break;
          case ParameterLocation.Query:
            queries.push(p);
            break;
          default:
            others.push(p);
            break;
        }
      } else {
        this.add(function* () {
          yield '';
        });
      }
      this.methodParameters.push(p);
    }
    [...paths, ...headers, ...queries, ...others].forEach(p => this.addParameter(p));

    if (baseUrl === '') {
      // Some services will make the host as an input parameter
      baseUrl = this.operation.requests ? this.operation.requests[0].protocol.http?.uri : '';
    }

    this.description = this.operation.language.csharp?.description || '';

    // add body paramter if there should be one.
    if (this.operation.requests && this.operation.requests.length && this.operation.requests[0].parameters && this.operation.requests[0].parameters.length) {
      // this request does have a request body.
      const param = this.operation.requests[0].parameters.find((p) => !p.origin || p.origin.indexOf('modelerfour:synthesized') < 0);
      if (param) {
        if (!viaJson) {
          this.bodyParameter = new OperationBodyParameter(this, 'body', param.language.default.description, param.schema, param.required ?? false, this.state, {
            // TODO: temp solution. We need a class like NewKnowMediaType
            mediaType: knownMediaType(KnownMediaType.Json),
            contentType: KnownMediaType.Json
          });
          this.addParameter(this.bodyParameter);
        } else {
          this.addParameter(
            new Parameter('jsonString', System.String, {
              description: `Json string supplied to the ${operation.language.csharp?.name} operation`,
            })
          );
        }
      }
    }

    for (const response of [...values(this.operation.responses), ...values(this.operation.exceptions)]) {
      const responseType = (<BinaryResponse>response).binary ? new Binary(new BinarySchema(''), true) : ((<SchemaResponse>response).schema ? state.project.modelsNamespace.NewResolveTypeDeclaration(<NewSchema>((<SchemaResponse>response).schema), true, state) : null);
      const headerType = response.language.default.headerSchema ? state.project.modelsNamespace.NewResolveTypeDeclaration(<NewSchema>response.language.default.headerSchema, true, state) : null;
      const newCallbackParameter = new CallbackParameter(response.language.csharp?.name || '', responseType, headerType, this.state, { description: response.language.csharp?.description });
      if (!withResult) {
        this.addParameter(newCallbackParameter);
      }
      this.callbacks.push(newCallbackParameter);
    }

    // add eventhandler parameter
    this.contextParameter = this.addParameter(new Parameter('eventListener', ClientRuntime.IEventListener, { description: `an <see cref="${ClientRuntime.IEventListener}" /> instance that will receive events.` }));

    // add optional parameter for sender
    this.senderParameter = this.addParameter(new Parameter('sender', ClientRuntime.ISendAsync, { description: `an instance of an ${ClientRuntime.ISendAsync} pipeline to use to make the request.` }));

    let rx = this.operation.requests ? this.operation.requests[0].protocol.http?.path : '';
    const path = rx;
    let pathWithoutOperation = path;
    // For post API, Some URI may contain an action string .e.x '/start' at the end
    // of the URI, for such cases, we will drop the action string if identityCorrection
    // is set in the configuration
    if (this.operation.requests && this.operation.requests.length && this.operation.requests[0].protocol.http?.method === 'post' && this.state.project.identityCorrection) {
      const idx = rx.lastIndexOf('/');
      rx = rx.substr(0, idx);
      pathWithoutOperation = rx;
    }

    let url = `/${path.startsWith('/') ? path.substr(1) : path}`;


    const serverParams = this.methodParameters.filter(each => each.param.protocol.http?.in === ParameterLocation.Uri);

    const headerParams = this.methodParameters.filter(each => each.param.protocol.http?.in === ParameterLocation.Header);
    const pathParams = this.methodParameters.filter(each => each.param.protocol.http?.in === ParameterLocation.Path);
    const queryParams = this.methodParameters.filter(each => each.param.protocol.http?.in === ParameterLocation.Query);
    const cookieParams = this.methodParameters.filter(each => each.param.protocol.http?.in === ParameterLocation.Cookie);

    // replace any server params in the uri
    for (const pp of serverParams) {
      url = url.replace(`{${pp.param.language.default.serializedName}}`, `"
        + ${pp.name}
        + "`);
    }

    for (const pp of pathParams) {
      rx = rx.replace(`{${pp.param.language.default.serializedName}}`, `(?<${pp.param.language.default.serializedName}>[^/]+)`);

      if (this.viaIdentity) {
        url = url.replace(`{${pp.param.language.default.serializedName}}`, `"
        + ${pp.name}
        + "`);
      } else {
        url = url.replace(`{${pp.param.language.default.serializedName}}`, `"
        + ${removeEncoding(pp, '', KnownMediaType.UriParameter)}
        + "`);
      }
    }
    rx = `"^${rx}$"`;
    url = url.replace(/\s*\+ ""/gm, '');

    const bp = this.bodyParameter;

    if (bp) {
      this.serializationMode = ClientRuntime.SerializationMode.IncludeCreateOrUpdate;
      if (operation.language.default.name === 'Patch') {
        this.serializationMode = ClientRuntime.SerializationMode.IncludeUpdate;
      }
      // add optional parameter for json serialization mode
      this.serializationModeParameter = this.addParameter(new Parameter('serializationMode', ClientRuntime.SerializationMode, { description: `Allows the caller to choose the depth of the serialization. See <see cref="${ClientRuntime.SerializationMode}"/>.`, defaultInitializer: this.serializationMode }));
    }
    // add method implementation...

    this.add(function* () {
      const eventListener = new EventListener($this.contextParameter, $this.state.project.emitSignals, withResult);

      yield EOL;

      if ($this.viaIdentity) {
        yield '// verify that Identity format is an exact match for uri';
        yield EOL;

        const match = Local('_match', `${System.Text.RegularExpressions.Regex.new(rx, 'global::System.Text.RegularExpressions.RegexOptions.IgnoreCase').value}.Match(${identity.value})`);
        yield match.declarationStatement;
        yield If(`!${match}.Success`, `throw new global::System.Exception("Invalid identity for URI '${pathWithoutOperation}'");`);
        yield EOL;
        yield '// replace URI parameters with values from identity';
        for (const pp of pathParams) {
          yield `var ${pp.name} = ${match.value}.Groups["${pp.param.language.default.serializedName}"].Value;`;
        }
      }

      yield '// construct URL';
      const pathAndQueryV = Local('pathAndQuery', `${System.Text.RegularExpressions.Regex.declaration}.Replace(
        "${url}"
        ${queryParams.length > 0 ? '+ "?"' : ''}${queryParams.joinWith(pp => `
        + ${removeEncoding(pp, pp.param.language.default.serializedName, KnownMediaType.QueryParameter)}`, `
        + "&"`
)}
        ,"\\\\?&*$|&*$|(\\\\?)&+|(&)&+","$1$2")`.replace(/\s*\+ ""/gm, ''));
      yield pathAndQueryV.declarationStatement;

      yield EOL;

      yield eventListener.signal(ClientRuntime.Events.URLCreated, pathAndQueryV.value);
      yield EOL;

      yield '// generate request object ';
      const urlV = new LocalVariable('_url', dotnet.Var, {
        initializer: System.Uri.new(`$"${baseUrl}{${pathAndQueryV.value}}"`)
      });
      yield urlV.declarationStatement;
      const method = $this.operation.requests ? $this.operation.requests[0].protocol.http?.method : '';
      yield `var request =  ${System.Net.Http.HttpRequestMessage.new(`${ClientRuntime.fullName}.Method.${method.capitalize()}, ${urlV.value}`)};`;
      yield eventListener.signal(ClientRuntime.Events.RequestCreated, 'request.RequestUri.PathAndQuery');
      yield EOL;

      if (length(headerParams) > 0) {
        yield '// add headers parameters';
        for (const hp of headerParams) {
          if (hp.param.language.default.name === 'Content-Length') {
            // content length is set when the request body is set
            continue;
          }
          yield hp.serializeToContainerMember(KnownMediaType.Header, new LocalVariable('request.Headers', dotnet.Var), hp.param.language.default.serializedName, ClientRuntime.SerializationMode.None);
        }
        yield EOL;
      }
      yield eventListener.signal(ClientRuntime.Events.HeaderParametersAdded);

      if (bp) {
        yield '// set body content';
        yield `request.Content = ${bp.serializeToContent(bp.mediaType, new LiteralExpression('serializationMode'))};`;
        yield `request.Content.Headers.ContentType = ${System.Net.Http.Headers.MediaTypeHeaderValue.Parse(bp.contentType)};`;
        yield eventListener.signal(ClientRuntime.Events.BodyContentSet);
      }

      if (viaJson) {
        yield '// set body content';
        yield 'request.Content = new global::System.Net.Http.StringContent(jsonString, global::System.Text.Encoding.UTF8);';
        yield 'request.Content.Headers.ContentType = global::System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json");';
        yield eventListener.signal(ClientRuntime.Events.BodyContentSet);
      }

      yield '// make the call ';
    });
  }