Skip to content

ClientModel: Convince ourselves that the virtual problem isn't a concern #41234

@annelo-msft

Description

@annelo-msft

At a high level

  • If we newslot a property that is virtual in Azure.Core, if a type derives from the Azure.Core type and doesn't call the base type in System.ClientModel, values on the System.ClientModel type may not get set correctly.
  • When properties on PipelineResponse don't get set, policies can work incorrectly and this can cause breaking changes to existing Azure.Core-based clients.

A simple description of how this problem works is described here: https://gist.github.com/annelo-msft/73d14d238ecc61ddb287894067469598

In our code base, I discovered this when:

  1. Storage test sets MockResponse on message in its MockTransport
  2. Azure.Core's TransportPolicy sets IsError on Response - which sets it on MockResponse only and not in base PipelineResponse type
  3. ClientModel RetryPolicy checks IsError to determine whether or not to retry
    a. IsError is set to true on MockResponse, but false on base PipelineResponse
  4. Incorrect behavior happens as a result of incorrect logic in ClientModel RetryPolicy, which only uses values on PipelineResponse

Generalizing this:

  • Any virtual member on an Azure.Core type can be overridden by a subtype
  • If it is not also virtual on the base type, the override doesn't propagate up to the base type member, so the ClientModel values may not get set
  • If ClientModel-only logic depends on the value of the base type member, it can be incorrect

Concerns I have as a result of this

  • I think we have to make ClientModel members virtual if Azure.Core members are virtual, which is unfortunate for the ClientModel UX
    • i.e. we cannot newslot to add virtual in Azure.Core and make the ClientModel member non-virtual
  • Do we have an unsolvable problem in the case where we have to newslot the member in order to change the type?
    • e.g. Response.Headers/PipelineResponse.Headers
    • e.g. Request.Uri, Request.Method, Request.Content, and Request.Headers

Full API description of Request and Response types

image

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions