Add endpoints manually with Swashbuckle.Swagger - c#

I'm using a CMS. So when I go to i.e. '/painter' its routed to the 'JobController'. /plumber is also routed to 'JobController'.
Besides that it's MVC and not WebAPI, so swagger doesn't discover it, which is understandable and fine.
But I've a usecase, where if I access /pianter?json=1 it returnes json instead of HTML.
So as an API UI we would like to expose this 'fake' endpoint, just so the designers can see the output model.
So can I add an entirely fake endpoint - just to have a single userinterface between the designers and developers in swagger UI?
Besides having a visual UI, we want to generate some TypeScript based on the openapi standard.

Here is an option to create Fake endpoint with swashbuckle using IDocumentFilter:
private class DocumentFilterAddFakes : IDocumentFilter
{
private PathItem FakePathItem(int i)
{
var x = new PathItem();
x.get = new Operation()
{
tags = new[] { "Fake" },
operationId = "Fake_Get" + i.ToString(),
consumes = null,
produces = new[] { "application/json", "text/json", "application/xml", "text/xml" },
parameters = new List<Parameter>()
{
new Parameter()
{
name = "id",
#in = "path",
required = true,
type = "integer",
format = "int32"
}
},
};
x.get.responses = new Dictionary<string, Response>();
x.get.responses.Add("200", new Response() { description = "OK", schema = new Schema() { type = "string" } });
return x;
}
public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
{
for (int i = 0; i < 10; i++)
{
swaggerDoc.paths.Add("/Fake/" + i + "/{id}", FakePathItem(i));
}
}
}
Here is the result of something like that:
http://swashbuckletest.azurewebsites.net/swagger/ui/index#/Fake
The full code behind that is on github:
https://github.com/heldersepu/SwashbuckleTest/blob/master/Swagger_Test/App_Start/SwaggerConfig.cs#L316

Related

Making DialogFlow v2 DetectIntent Calls w/ C# (including input context)

So I finally figured out a way to successfully make detect intent calls and provide an input context. My question is whether or not this is the CORRECT (or best) way to do it:
(And yes, I know you can just call DetectIntent(agent, session, query) but I have to provide a input context(s) depending on the request)
var query = new QueryInput
{
Text = new TextInput
{
Text = model.Content,
LanguageCode = string.IsNullOrEmpty(model.Language) ? "en-us" : model.Language,
}
};
var commonContext = new global::Google.Cloud.Dialogflow.V2.Context
{
ContextName = new ContextName(agent, model.sessionId, "my-input-context-data"),
LifespanCount = 3,
Parameters = new Struct
{
Fields = {
{ "Source", Value.ForString(model.Source) },
{ "UserId" , Value.ForString(model.UserId.ToString())},
{ "Name" , Value.ForString(model.FirstName)}
}
}
};
var request = new DetectIntentRequest
{
SessionAsSessionName = new SessionName(agent, model.sessionId),
QueryParams = new QueryParameters
{
GeoLocation = new LatLng {Latitude = model.Latitude, Longitude = model.Longitude},
TimeZone = model.TimeZone ?? "MST"
},
QueryInput = query
};
request.QueryParams.Contexts.Add(commonContext);
// ------------
var creds = GetGoogleCredentials("myCredentials.json");
var channel = new Grpc.Core.Channel(SessionsClient.DefaultEndpoint.Host, creds.ToChannelCredentials());
var client = SessionsClient.Create(channel);
var response = client.DetectIntent(request);
channel.ShutdownAsync();
return response;
Note: I included the explicit ShutDownAsync (it's not in an async call) because I was getting some file locking issues when attempting to re-deploy the WebAPI project (and only after having executed this code).
Thanks
Chris
Updated 4/25: The most basic way I use this is to integrate the user's name into intent responses:
It can also be read from within the webhook/inline fulfillment index.js:
const name = request.body.queryResult && request.body.queryResult.outputContexts && request.body.queryResult.outputContexts[0].parameters.Name

Authenticating swagger with identityserver3 using .net 4.5

I am having some issues getting swagger to work with oauth2.
I have created a client in my database like this:
private static void CreateSwaggerClient(DatabaseContext context)
{
var client = new Client
{
ClientId = "swaggerui",
ClientName = "Swagger UI client",
Flow = Flows.Implicit,
Enabled = true,
EnableLocalLogin = true,
AccessTokenType = AccessTokenType.Reference,
AllowAccessTokensViaBrowser = true,
IdentityTokenLifetime = 300,
AccessTokenLifetime = 3600,
AuthorizationCodeLifetime = 300,
AbsoluteRefreshTokenLifetime = 2592000,
SlidingRefreshTokenLifetime = 1296000,
RedirectUris = new List<ClientRedirectUri>
{
new ClientRedirectUri { Uri = "http://localhost:62668/swagger" }
},
AllowedScopes = new List<ClientScope>()
{
new ClientScope
{
Scope = "api"
}
},
ClientSecrets = new List<ClientSecret>()
{
new ClientSecret
{
Value = "secret".Sha256(),
Type = "SharedSecret"
}
}
};
context.Clients.Add(client);
context.SaveChanges();
}
Which has access to my api Scope:
private static void CreateScope(DatabaseContext context)
{
var scope = new Scope
{
Enabled = true,
Name = "api",
DisplayName = "Cormar API",
Description = "Should only be used for trusted internal service side applications",
Required = true,
Emphasize = true,
Type = (int)ScopeType.Resource,
IncludeAllClaimsForUser = false,
ShowInDiscoveryDocument = true,
AllowUnrestrictedIntrospection = true,
ScopeClaims = new List<ScopeClaim>()
{
new ScopeClaim
{
Name = "role",
Description = "Role claim types",
AlwaysIncludeInIdToken = true
},
new ScopeClaim
{
Name = "name",
Description = "The name of the user",
AlwaysIncludeInIdToken = true
},
new ScopeClaim
{
Name ="password",
Description = "Contains the encrypted password for a user",
AlwaysIncludeInIdToken = true
}
},
ScopeSecrets = new List<ScopeSecret>()
{
new ScopeSecret
{
Value = "anothersecret".Sha256(),
Type = "SharedSecret"
}
}
};
context.Scopes.Add(scope);
context.SaveChanges();
}
If I open a browser and navigate to the authorize url like this: https://localhost:44313/identity/connect/authorize?client_id=swaggerui&redirect_uri=http://localhost:62668/swagger&response_type=token&scope=api&state=moo it takes me to a login page, which when I type the username and password brings me to the swagger page with a access_token appended to the URL like this:
#access_token=b49fe5641519c325c17d248d2372d69f&token_type=Bearer&expires_in=3600&scope=api&state=moo
But the issue here is that if I click anything, the access token is removed from the url and if I try any of my endpoints, they all fail with access denied.
I have setup my swagger config like this:
private static void ConfigureSwagger(HttpConfiguration config)
{
config.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "test API");
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
var commentsFileName = Assembly.GetExecutingAssembly().GetName().Name + ".XML";
var commentsFile = Path.Combine(baseDirectory, "bin", commentsFileName);
c.IncludeXmlComments(commentsFile);
c.OAuth2("oauth2")
.Description("OAuth2 Implicit Grant")
.Flow("implicit")
.AuthorizationUrl("http://localhost:62668/identity/connect/authorize")
.TokenUrl("http://localhost:62668/identity/connect/token")
.Scopes(scopes =>
{
scopes.Add("api", "api access");
});
c.OperationFilter<AssignOAuth2SecurityRequirements>();
}).EnableSwaggerUi(c =>
{
c.EnableOAuth2Support("swaggerui", "secret", "local", "test");
});
}
Can anyone tell me what I am missing?
I managed to get this working.
First of all, my AssignOAuth2SecurityRequirements was setup incorrectly. I actually found the right code here: http://knowyourtoolset.com/2015/08/secure-web-apis-with-swagger-swashbuckle-and-oauth2-part-2/
public class AssignOAuth2SecurityRequirements: IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
var actFilters = apiDescription.ActionDescriptor.GetFilterPipeline();
var allowsAnonymous = actFilters.Select(f => f.Instance).OfType<OverrideAuthorizationAttribute>().Any();
if (allowsAnonymous)
return; // must be an anonymous method
//var scopes = apiDescription.ActionDescriptor.GetFilterPipeline()
// .Select(filterInfo => filterInfo.Instance)
// .OfType<AllowAnonymousAttribute>()
// .SelectMany(attr => attr.Roles.Split(','))
// .Distinct();
if (operation.security == null)
operation.security = new List<IDictionary<string, IEnumerable<string>>>();
var oAuthRequirements = new Dictionary<string, IEnumerable<string>>
{
{"oauth2", new List<string> {"api"}}
};
operation.security.Add(oAuthRequirements);
}
}
Next, the redirect_uris for my client were incorrect. They all have to be https and they need the full redirect uri. Mine became this:
new ClientRedirectUri { Uri = "https://localhost:44313/swagger/ui/o2c-html" },
Once these were set up, it all started working.

YouTrack REST API - Create new priority

I I’m looking for a way to create a new priority value with the REST API.
In the documentation I found the following endpoint:
/rest/admin/customfield/bundle/{bundleName}/{fieldValue}?{description}&{colorIndex}
Calling this endpoint returns a 415 status code with the content:
{"value":"Unsupported Media Type"}
Here is my code:
var connection = YouTrackConnectionFactory.GetConnection();
var client = await connection.GetAuthenticatedHttpClient();
var priorityValue = "SomeNewPrio";
var enumerationName = "Priorities";
var queryString = new Dictionary<String, String>
{
{ "bundleName", enumerationName },
{ "fieldValue", priorityValue },
{ "description", WebUtility.UrlEncode( "Automatically created priority" ) },
{ "colorIndex", "9" }
};
var response = await client.PutAsync( $"/rest/admin/customfield/bundle/{enumerationName}/{priorityValue}", new FormUrlEncodedContent( queryString ) );
response.EnsureSuccessStatusCode();
Is there something wrong with my data or is there another endpoint I should be using?

Fire TriggeredSends from ExactTarget's API using HttpClient REST

I've read along the way that Salesforce (I'm extremely new to this 3rd party platform) has a FUEL SDK which one can use instead of the version (using HttpClient -- REST instead of SOAP).
Please correct me if using FUEL SDK is the only way to go about requesting Salesforce's endpoints. Currently I am attempting to hit ExactTargets's API endpoints using HttpClient. These are the tutorials I've been basing my code off of:
https://developer.salesforce.com/docs/atlas.en-us.mc-apis.meta/mc-apis/messageDefinitionSends.htm
https://developer.salesforce.com/docs/atlas.en-us.mc-getting-started.meta/mc-getting-started/get-access-token.htm
Wanted Result:
To be able to request a Triggered Send email based off a template inside of ExactTarget.
Problem:
The Salesforce endpoint continuously returns a 404. I am able to receive the authorization token successfully. The GetAccessToken method is omitted for brevity
https://www.exacttargetapis.com/messaging/v1/messageDefinitionSends/key:MyExternalKey/send
I do not understand why the 2nd POST request to //www.exacttargetapis.com/..... returns a 404 but the authorization works. This leads me to believe that I do not have to use the FUEL SDK to accomplish triggering a welcome email.
Code:
private const string requestTokenUrl = "https://auth.exacttargetapis.com/v1/requestToken";
private const string messagingSendUrl = "https://www.exacttargetapis.com/messaging/v1/messageDefinitionSends";
private string exactTargetClientId = ConfigurationManager.AppSettings["ExactTargetClientId"];
private string exactTargetClientSecret = ConfigurationManager.AppSettings["ExactTargetClientSecret"];
private string TriggerEmail(User model, string dbName)
{
var etExternalKeyAppSetting = ConfigurationManager.AppSettings.AllKeys.FirstOrDefault(x => x.Equals(dbName));
if (etExternalKeyAppSetting != null)
{
string etExternalKey = ConfigurationManager.AppSettings[etExternalKeyAppSetting];
HttpClient client = new HttpClient
{
BaseAddress = new Uri(string.Format(#"{0}/key:{1}/send", messagingSendUrl, etExternalKey)),
DefaultRequestHeaders =
{
Authorization = new AuthenticationHeaderValue("Bearer", this.GetAccessToken())
}
};
try
{
var postData = this.CreateExactTargetPostData(model.Email, etExternalKey);
var response = client.PostAsync(client.BaseAddress
, new StringContent(JsonConvert.SerializeObject(postData).ToString()
, Encoding.UTF8
, "application/json")).Result;
// get triggered email response
if (response.IsSuccessStatusCode)
{
dynamic result = JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result);
}
}
catch (Exception ex)
{
string message = ex.Message;
}
}
return "testing";
}
private object CreateExactTargetPostData(string email, string extKey)
{
var fromData = new
{
Address = ConfigurationManager.AppSettings["AwsSenderEmail"],
Name = "Test"
};
var subscriberAttributes = new { };
var contactAttributes = new
{
SubscriberAttributes = subscriberAttributes
};
var toData = new
{
Address = email,
//SubscriberKey = extKey,
//ContactAttributes = contactAttributes
};
var postData = new
{
From = fromData,
To = toData
};
return postData;
}
I have also tried using Advanced REST Client using the following:
URL:
https://www.exacttargetapis.com/messaging/v1/messageDefinitionSends/key:MyExternalKey/send
POST
Raw Headers:
Content-Type: application/json
Authorization: Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Raw Payload:
{
"From": {
"Address": "code#exacttarget.com",
"Name": "Code#"
},
"To": {
"Address": "example#example.com",
"SubscriberKey": "example#example.com",
"ContactAttributes": {
"SubscriberAttributes": {
"Region": "West",
"City": "Indianapolis",
"State": "IN"
}
}
},
"OPTIONS": {
"RequestType": "ASYNC"
}
}
Issue was my App in the AppCenter was pointing to the incorrect login for MarketingCloud =(

Xamarin: Using HttpClient POST in combination with a dynamic Class

I have some services that require rather complex objects. Every service uses almost the same base object but it needs to be extended for each service.
A simple example:
The Standard Object would be something like:
ContextObject {
params {
Device {
Name: "MyMobileDevice",
ID: 123455691919238
}
}
}
and for my service I need to add some properties under params,
something like:
ContextObject {
params {
Device {
Name: "MyMobileDevice",
ID: 123455691919238
},
requested_employee_id: 112929
}
}
I tried to get this by using JObject and got it working so far but now I cant find a proper example on how to send this object to my server using HttpClient.
Edit:
Here is my full JObject which all Requests need:
public static JObject DefaultContext (string ServiceMethod) {
var Context = new JObject();
Context["version"] = "1.1";
Context["method"] = ServiceMethod;
Context["params"] = JObject.FromObject( new {
Context = JObject.FromObject( new {
User = App.UserSettings.USERNAME,
Password = App.UserSettings.PASSWORD,
SerialNumber = "1234567890", // TODO: use generated id
Locale = "de-DE",
Timestamp = DateTime.Now.ToString("yyyy-MM-ddTHH\\:mm\\:ss.fffzzz"),
Device = JObject.FromObject( new {
DeviceType = "phone",
ProductType = "D6603", // TODO: Get from Device-Info
screen = JObject.FromObject( new {
Density = "xxhdpi", // TODO: Get from Device-Info
resolution = JObject.FromObject( new {
Height = "1920", // TODO: Get from Device-Info
Width = "1080" // TODO: Get from Device-Info
})
}),
version = JObject.FromObject( new {
AppVersion = "myAppVersion", // TODO: Get App-Information LayoutVersion = "1.0"
} )
})
})
});
return mobileContext;
}
For my Requests I need to add parameters under the "params"-Node. Which works with:
mobileContext["params"]["mynewparameter"] = "FOO";
Now I wanted to send this JObject via System.Net.Http-Client to my server with something like this:
var client = new HttpClient ();
client.BaseAddress = new Uri (App.UserSettings.HOST + ":" + App.UserSettings.PORT + App.UserSettings.TYPE);
client.Timeout = 3000;
var context = MyContext.DefaultContext (ServiceMethods.CUSTOMER_LIST_METHOD);
context ["params"] ["myrequestparam"] = "FOO";
var jsonString = JsonConvert.SerializeObject (context);
var responseData = await client.Get???????
Is my general approach correct? How would you do it? Is there a sample on how to handle such dynamic stuff?
I couldn't find a example on how to use httpclient correctly with the Newtonsoft.JSON-Library how far am I from actually working code?

Categories