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