in powershell/llcsharp/operation/method.ts [416:658]
yield Try(function* () {
const responder = function* () {
// TODO: omit generating _contentType var if it will never be used
// const contentType = new LocalVariable('_contentType', dotnet.Var, { initializer: `_response.Content.Headers.ContentType?.MediaType` });
const contentType = Local('_contentType', `${response}.Content.Headers.ContentType?.MediaType`);
yield contentType;
// add response handlers
yield Switch(`${response}.StatusCode`, function* () {
const responses = [...values(opMethod.operation.responses), ...values(opMethod.operation.exceptions)].sort(function (a, b) { return (<string>(a.protocol.http?.statusCodes[0])).localeCompare(<string>(b.protocol.http?.statusCodes[0])); });
for (const resp of responses) {
const responseCode = resp.protocol.http?.statusCodes[0];
if (responseCode !== 'default'/*TODO: !== not found, handle other exception response */) {
const leadNum = parseInt(responseCode[0]);
// will use enum when it can, fall back to casting int when it can't
if (withResult) {
yield TerminalCase(System.Net.HttpStatusCode[responseCode] ? System.Net.HttpStatusCode[responseCode].value : `${System.Net.HttpStatusCode.declaration} n when((int)n >= ${leadNum * 100} && (int)n < ${leadNum * 100 + 100})`, $this.responsesEmitter($this, opMethod, [resp], response, eventListener, withResult));
} else {
yield Case(System.Net.HttpStatusCode[responseCode] ? System.Net.HttpStatusCode[responseCode].value : `${System.Net.HttpStatusCode.declaration} n when((int)n >= ${leadNum * 100} && (int)n < ${leadNum * 100 + 100})`, $this.responsesEmitter($this, opMethod, [resp], response, eventListener, false));
}
} else {
if (withResult) {
yield TerminalDefaultCase($this.responsesEmitter($this, opMethod, [resp], response, eventListener, withResult));
} else {
yield DefaultCase($this.responsesEmitter($this, opMethod, [resp], response, eventListener, false));
}
}
}
// missing default response?
if (!opMethod.operation.exceptions) {
// if no default, we need one that handles the rest of the stuff.
yield TerminalDefaultCase(function* () {
yield `throw new ${ClientRuntime.fullName}.UndeclaredResponseException(_response);`;
});
}
});
};
const originalUri = Local('_originalUri', new LiteralExpression(`${reqParameter.use}.RequestUri.AbsoluteUri`));
if ($this.opMethod.operation.language.csharp?.lro) {
yield '// this operation supports x-ms-long-running-operation';
yield originalUri;
}
// try statements
const sendTask = Local(
'sendTask',
new LiteralExpression(
`${opMethod.senderParameter.value}.SendAsync(${reqParameter.use}, ${opMethod.contextParameter.value})`
)
);
yield sendTask;
// delay sending BeforeCall event until URI has been replaced by HTTP pipeline
yield eventListener.signal(ClientRuntime.Events.BeforeCall, reqParameter.use);
if ($this.opMethod.operation.language.csharp?.lro) {
yield eventListener.signal(ClientRuntime.Events.Progress, new LiteralExpression('"intentional placeholder"'), new LiteralExpression('0'));
}
yield `${response.value} = await ${sendTask.value}; `;
yield eventListener.signal(ClientRuntime.Events.ResponseCreated, response.value);
const EOL = 'EOL';
// LRO processing (if appropriate)
if ($this.opMethod.operation.language.csharp?.lro) {
yield `// declared final-state-via: ${$this.opMethod.operation.language.csharp.lro['final-state-via']}`;
const fsv = $this.opMethod.operation.language.csharp.lro['final-state-via'];
let finalUri: LocalVariable;
switch (fsv) {
case 'original-uri':
// perform a final GET on the original URI.
finalUri = originalUri;
break;
case 'location':
// perform a final GET on the uri in Location header
finalUri = Local('_finalUri', response.invokeMethod('GetFirstHeader', new StringExpression('Location')));
yield finalUri;
break;
case 'operation-location':
// perform a final GET on the uri in Operation-Location header
finalUri = Local('_finalUri', response.invokeMethod('GetFirstHeader', new StringExpression('Operation-Location')));
yield finalUri;
break;
case 'azure-asyncoperation':
case 'azure-async-operation':
//depending on the type of request, do the appropriate behavior
switch ($this.opMethod.operation.requests?.[0].protocol.http?.method.toLowerCase()) {
case 'post':
case 'delete':
finalUri = Local('_finalUri', response.invokeMethod('GetFirstHeader', new StringExpression('Azure-AsyncOperation')));
yield finalUri;
break;
case 'patch':
case 'put':
// perform a final GET on the original URI.
finalUri = originalUri;
break;
}
break;
default:
// depending on the type of request, fall back to the appropriate behavior
if ($this.opMethod.operation.requests) {
switch ($this.opMethod.operation.requests[0].protocol.http?.method.toLowerCase()) {
case 'post':
case 'delete':
finalUri = Local('_finalUri', response.invokeMethod('GetFirstHeader', new StringExpression('Location')));
yield finalUri;
break;
case 'patch':
case 'put':
// perform a final GET on the original URI.
finalUri = originalUri;
break;
}
}
break;
}
const asyncOperation = Local('asyncOperation', response.invokeMethod('GetFirstHeader', new StringExpression('Azure-AsyncOperation')));
yield asyncOperation;
const location = Local('location', response.invokeMethod('GetFirstHeader', new StringExpression('Location')));
yield location;
const operationLocation = Local('operationLocation', response.invokeMethod('GetFirstHeader', new StringExpression('Operation-Location')));
yield operationLocation;
yield While(new LiteralExpression(`${reqParameter.use}.Method == System.Net.Http.HttpMethod.Put && ${response.value}.StatusCode == ${System.Net.HttpStatusCode[200].value} || ${response.value}.StatusCode == ${System.Net.HttpStatusCode[201].value} || ${response.value}.StatusCode == ${System.Net.HttpStatusCode[202].value} `), function* () {
yield '// delay before making the next polling request';
yield eventListener.signal(ClientRuntime.Events.DelayBeforePolling, response.value);
yield EOL;
yield '// while we wait, let\'s grab the headers and get ready to poll. ';
yield 'if (!System.String.IsNullOrEmpty(_response.GetFirstHeader(@"Azure-AsyncOperation"))) {';
yield ' ' + asyncOperation.assign(response.invokeMethod('GetFirstHeader', new StringExpression('Azure-AsyncOperation')));
yield '}';
yield 'if (!global::System.String.IsNullOrEmpty(_response.GetFirstHeader(@"Location"))) {';
yield ' ' + location.assign(response.invokeMethod('GetFirstHeader', new StringExpression('Location')));
yield '}';
yield 'if (!global::System.String.IsNullOrEmpty(_response.GetFirstHeader(@"Operation-Location"))) {';
yield ' ' + operationLocation.assign(response.invokeMethod('GetFirstHeader', new StringExpression('Operation-Location')));
yield '}';
const uriLocal = Local('_uri', Ternery(
System.String.IsNullOrEmpty(asyncOperation),
Ternery(System.String.IsNullOrEmpty(location),
Ternery(System.String.IsNullOrEmpty(operationLocation),
originalUri,
operationLocation
),
location),
asyncOperation));
yield uriLocal;
yield `${reqParameter.use} = ${reqParameter.use}.CloneAndDispose(${System.Uri.new(uriLocal)}, ${ClientRuntime.Method.Get});`;
yield EOL;
yield '// and let\'s look at the current response body and see if we have some information we can give back to the listener';
const content = Local('content', new LiteralExpression(`await ${response.value}.Content.ReadAsStringAsync()`));
yield content;
yield EOL;
yield '// drop the old response';
yield `${response.value}?.Dispose();`;
yield EOL;
yield '// make the polling call';
yield `${response.value} = await ${opMethod.senderParameter}.SendAsync(${reqParameter.value}, ${opMethod.contextParameter});`;
yield eventListener.signal(ClientRuntime.Events.Polling, response.value);
yield EOL;
yield `
// if we got back an OK, take a peek inside and see if it's done
if( ${response.value}.StatusCode == ${System.Net.HttpStatusCode.OK})
{
var error = false;
try {
if( ${ClientRuntime.JsonNode.Parse(toExpression(`await ${response.value}.Content.ReadAsStringAsync()`))} is ${ClientRuntime.JsonObject} json)
{
var state = json.Property("properties")?.PropertyT<${ClientRuntime.JsonString}>("provisioningState") ?? json.PropertyT<${ClientRuntime.JsonString}>("status");
if( state is null )
{
// the body doesn't contain any information that has the state of the LRO
// we're going to just get out, and let the consumer have the result
break;
}
switch( state?.ToString()?.ToLower() )
{
case "failed":
error = true;
break;
case "succeeded":
case "canceled":
// we're done polling.
break;
default:
// need to keep polling!
${response.value}.StatusCode = ${System.Net.HttpStatusCode.Created};
continue;
}
}
} catch {
// if we run into a problem peeking into the result,
// we really don't want to do anything special.
}
if (error) {
throw new ${ClientRuntime.fullName}.UndeclaredResponseException(${response.value});
}
}`;
yield EOL;
yield '// check for terminal status code';
yield If(new LiteralExpression(`${response.value}.StatusCode == ${System.Net.HttpStatusCode[201].value} || ${response.value}.StatusCode == ${System.Net.HttpStatusCode[202].value} `), 'continue;');
yield '// we are done polling, do a request on final target?';
switch (fsv) {
case 'original-uri':
case 'azure-asyncoperation':
case 'azure-async-operation':
case 'location':
case 'operation-location':
// perform a final GET on the specified final URI.
yield $this.finalGet(eventListener, finalUri, reqParameter, response);
break;
default:
yield If(`!string.IsNullOrWhiteSpace(${finalUri})`, function* () {
yield $this.finalGet(eventListener, finalUri, reqParameter, response);
});
break;
}
});
}
yield eventListener.signal(ClientRuntime.Events.Progress, new LiteralExpression('"intentional placeholder"'), new LiteralExpression('100'));
yield responder();
});