I am new to C# and Serverless development. I am trying to create an AWS Lambda that has an API Gateway trigger. When the Lambda triggers I want to write a User record to the database.
Lambda:
namespace CreateProfile;
using System.Net;
using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.Core;
using Database;
using Users.Models;
public class Function
{
/// <summary>
/// This Lambda function is for creating a user profile
/// </summary>
public APIGatewayHttpApiV2ProxyResponse FunctionHandler(User user, ILambdaContext context)
{
LambdaLogger.Log($"Calling function name: {context.FunctionName}\n");
LambdaLogger.Log($"Payload Received: {user}");
// 1. Populate the relevant table(s) from our input
using myDbContext ctx = new();
ctx.Users.Add(user);
ctx.SaveChanges();
APIGatewayHttpApiV2ProxyResponse response = new ()
{
StatusCode = (int)HttpStatusCode.OK,
Body = "Great Scott...it worked!",
Headers = new Dictionary<string, string> { { "Content-Type", "text/plain" } }
};
return response;
}
}
I am using the following Assembly:
using Amazon.Lambda.Core;
using Amazon.Lambda.Serialization.SystemTextJson;
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(
DefaultLambdaJsonSerializer
))]
I am using the following as my database context:
namespace Database;
using Users.Models;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using Npgsql;
[DbConfigurationType(typeof(Config))]
public class MyDbContext: DbContext
{
public myDbContext(): base(MakeConnString()) {}
private static string MakeConnString()
{
// Will be moving these to a common location
string OptEnv(string key, string default_) =>
Environment.GetEnvironmentVariable(key) ?? default_;
string Env(string key) =>
Environment.GetEnvironmentVariable(key) ?? throw new MissingFieldException(key);
NpgsqlConnectionStringBuilder builder = new()
{
Host = Env("PGHOST"),
Port = int.Parse(OptEnv("PGPORT", "5432")),
SslMode = Enum.Parse<SslMode>(OptEnv("PGSSLMODE", "Require")),
TrustServerCertificate = true,
Database = OptEnv("PGDATABASE", "postgres"),
Username = OptEnv("PGUSER", "postgres"),
Password = Env("PGPASSWORD")
};
return builder.ConnectionString;
}
public DbSet<User> Users { get; set; }
}
When running this my Lambda hangs and I can't figure out why.
I'm assuming the database you are trying to interact with is an RDS instance or running on an EC2 instance in the same account, right?
If so, are your Lambda function deployed into your VPC? If not, the Lambda needs to be in order to talk to a VPC resource. The default is the Lambdas are NOT deployed in your VPC.
If you are using Serverless Framework then you need to add the following config to the provider section of your serverless.yml [https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml]
provider:
# Optional VPC settings
# If you use VPC then both securityGroupIds and subnetIds are required
vpc:
securityGroupIds:
- securityGroupId1
subnetIds:
- subnetId1
- subnetId2
The subnets you reference need to have a route to the subnets your database is provisioned into. They can be in the same subnets as the ones your RDS instance or EC2 is running the in DB.
Lastly, you need to ensure that the Security Group allows outbound traffic on the correct port for your Lambda Security Group, as well as, ensure that the Security Group on your database (EC2 or RDS) allows traffic from either the Lambda SG or the CIDR/IP ranges of the subnets you are deploying the Lambdas into on the correct port #.
The hanging is typically the request not making it to the DB - if you are already set up with your Lambda deployed in your VPC, then you should check the routing and Security Groups mentioned.
Related
For a project I'm working on I have to get a Pull Request and Repository from an Azure DevOps WorkItem ID.
I'm using the Microsoft.TeamFoundationServer.Client NuGet-Package for this.
Now i also want to be able to check if a build pipeline ran successfully before moving on to further steps.
After trying to figure it out myself and not finding a single article on how to do that, I'm just gonna ask the question myself.
So, I already have:
the WorkItem object
the GitRepository object
the PullRequest object
And I want:
some form of pipeline object of that specific Pull Request/Commit
I hope there even is a way to get that.
Any help or references are apprechiated. Thanks!
I'm working on I have to get a Pull Request and Repository from an
Azure DevOps WorkItem ID.
For pull request that related to work item, I can write a C# code for you. But for the repository, I think there doesn't have a relationship between repository itself and work item in DevOps concept(link commit and work item is possible.).
Now i also want to be able to check if a build pipeline ran
successfully before moving on to further steps.
Do you mean you want the pipeline run status related to pull request? I checked the sdk definition, there doesn't have such definition, also no in the REST API. A possible solution is following the f12 to capture the API to get the build pipeline run id and it status.
Just a demo:
using System;
using System.Threading.Tasks;
using Microsoft.TeamFoundation.Build.WebApi;
using Microsoft.TeamFoundation.SourceControl.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.WebApi;
namespace GetPipelineResults
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
string url_string = "https://dev.azure.com/xxx/";
string personalAccessToken = "xxx";
Uri orgUrl = new Uri(url_string);
string project = "xxx";
int workitemId = 122;
var workitem = GetPullRequestAndRepositoryFromWorkItemId(orgUrl,personalAccessToken,workitemId);
var pullRequestUrl = workitem.Result.Relations[0].Url.ToString();
var pullRequestUrl2 = pullRequestUrl.Substring(pullRequestUrl.LastIndexOf('/') + 1);
string[] pullRequestUrl2Array = pullRequestUrl2.Split("%2F");
string pullRequestIdString = pullRequestUrl2Array[pullRequestUrl2Array.Length - 1];
Console.WriteLine(pullRequestIdString);
}
//Get Pull request from work item id
public static async Task<WorkItem> GetPullRequestAndRepositoryFromWorkItemId(Uri orgUrl, string personalAccessToken, int workItemId)
{
VssConnection connection = new VssConnection(orgUrl, new VssBasicCredential(string.Empty, personalAccessToken));
WorkItemTrackingHttpClient workItemTrackingHttpClient = connection.GetClient<WorkItemTrackingHttpClient>();
WorkItemExpand workItemExpand = WorkItemExpand.All;
var workItem = workItemTrackingHttpClient.GetWorkItemAsync(workItemId, expand: workItemExpand).Result;
return workItem;
}
}
}
I have created a chat bot using microsoft bot framework v4 sdk. I wanted to log bot user and bot messages to cosmos db.
i am able to log only user messages using below blog https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-howto-v4-storage?view=azure-bot-service-4.0&tabs=csharp#using-cosmos-db .
I expect to log both user and bot responses.
Thankfully, this is pretty easy since ItranscriptLogger and TranscriptLoggerMiddleware already exist.
Create your TranscriptStore Class (new Class file)
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Azure;
using Microsoft.Bot.Schema;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace QuickTestBot_CSharp
{
public class CosmosTranscriptStore : ITranscriptLogger
{
private CosmosDbStorage _storage;
public CosmosTranscriptStore(CosmosDbStorageOptions config)
{
_storage = new CosmosDbStorage(config);
}
public async Task LogActivityAsync(IActivity activity)
{
// activity only contains Text if this is a message
var isMessage = activity.AsMessageActivity() != null ? true : false;
if (isMessage)
{
// Customize this to save whatever data you want
var data = new
{
From = activity.From,
To = activity.Recipient,
Text = activity.AsMessageActivity().Text,
};
var document = new Dictionary<string, object>();
// activity.Id is being used as the Cosmos Document Id
document.Add(activity.Id, data);
await _storage.WriteAsync(document, new CancellationToken());
}
}
}
}
Create and Add the Middleware (in Startup.cs)
[...]
var config = new CosmosDbStorageOptions
{
AuthKey = "<YourAuthKey>",
CollectionId = "<whateverYouWant>",
CosmosDBEndpoint = new Uri("https://<YourEndpoint>.documents.azure.com:443"),
DatabaseId = "<whateverYouWant>",
};
var transcriptMiddleware = new TranscriptLoggerMiddleware(new CosmosTranscriptStore(config));
var middleware = options.Middleware;
middleware.Add(transcriptMiddleware);
[...]
Result:
Note:
This is probably the easiest/best way to do it. However, you can also capture outgoing activities under OnTurnAsync() using turnContext.OnSendActivities() and then write the outgoing activity to storage, as well.
I have a small tool for transfer Entities from microsoft dynamics 365 crm 2016 instance to another one. I succesfully transfered entities that don't have any dependices; but when i try to transfer entities that some optionsets setted up -like language,verticals,departments- i get error beacause of these optionsets are not exists at target instance.
I signed these optionsets at below image.
My problem is I don't know how i can retrive these extensions programatically. I already used below code for retrive all optionsets but the user defined languages,verticals and other optionsets were not exists at repsonse.
RetrieveAllOptionSetsRequest retrieveAllOptionSetsRequest = new RetrieveAllOptionSetsRequest();
var retrieveAllOptionSetsResponse =(RetrieveAllOptionSetsResponse)sourceService.Execute(retrieveAllOptionSetsRequest);
Any Idea ? Which request should I send to source crm instance for get all user defined optionsets ?
Those entities may have private option sets. You can retrieve using those option sets for each entity using these methods (pass the entity's logical name to the entity parameter):
using System;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Metadata;
using Microsoft.Xrm.Tooling.Connector;
using System.Collections.Generic;
using System.Linq;
private List<AttributeMetadata> getPicklists(IOrganizationService svc, string entity)
{
return allAttributes(svc, entity).Where(a => a.AttributeType == AttributeTypeCode.Picklist).ToList();
}
//Retrieve all attributes of an entity
private List<AttributeMetadata> allAttributes(IOrganizationService svc, string entity)
{
var req = new RetrieveEntityRequest();
req.EntityFilters = EntityFilters.Attributes;
req.LogicalName = entity.ToLower();
var response = (RetrieveEntityResponse)svc.Execute(req);
return response.EntityMetadata.Attributes.ToList();
}
I'm following this example, ClientMongo to connect a WPF application to my MongoDB database via the connection string. But I get an error on the MongoClient when I call the GetServer method. The error states that GetServer doesn't exist, although the correct using references and usings have been added.
Can anyone spot if I've missed a step in setting this up? Or is there an alternative solution to create a connection with the remote DB?
This is the code I've used to connect, similar to the example above. The user and password have been starred out for privacy:
using MongoDB.Bson;
using MongoDB.Driver;
namespace MongoDBApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private string connectionString = "mongodb://<brian****>:<********123;>#ds048878.mongolab.com:48878/orders";
public MainWindow()
{
InitializeComponent();
var mongoUrl = MongoUrl.Create(connectionString);
var server = new MongoClient(connectionString).GetServer();
return server.GetDatabase(mongoUrl.DatabaseName);
}
}
}
If you are using the 2.x Version of the C# driver, forget about the Server object.
You can get your Database directly from the client:
var client = new MongoClient("<connectionString>");
return this.Client.GetDatabase("<databaseName>");
I'm having trouble publishing my Entity Framework database to azure.
I'm working with .NET framework 4.5 and EF 6.1.3. The way my project is set up is as follows and using a code first approach:
Class library for the domain entities(database entities)
Class library for the DTOs
Class library for a repository where I do all the CRUD operations with Entity
Web api project for just the web services(there's no presentation, just restful controllers).
My web services project has references to the repository library and the DTOs library and I never created the database explicitly because EF created it for me using SQL server express I believe, I set up the web.config as follows:
<connectionStrings>
<add name="Database" connectionString="Server=(localdb)\v11.0;Database=Database;Trusted_Connection=True;" providerName="System.Data.SqlClient" />
</connectionStrings>
In my project the database is created along with all the tables and relationships. I added some initial migrations in the repository library like this
namespace Project.Repository.Migrations
{
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;
internal sealed class Configuration : DbMigrationsConfiguration<Project.Repository.ProjectContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
protected override void Seed(Project.Repository.ProjectContext context)
{
Guid userId = new Guid();
Guid restaurantId = new Guid();
context.Users.AddOrUpdate(
u => u.Id, new Domain.Security.User { Id = userId, Age = 18, Description = "I like restaurants", Email = "user#gmail.com", Password = "12345", Username = "someuser" }
);
context.Restaurants.AddOrUpdate(
r => r.Id,
new Domain.Restaurants.Restaurant
{
Id = restaurantId,
Name = "mcdonalds",
Description = "best restaurant",
FacebookUrl = "www.facebook.com",
GoogleUrl = "www.google.com",
InstagramUrl = "www.instagram.com",
TwitterUrl = "www.twitter.com",
Votes = 3.5f,
UsersWhoLike = new List<Domain.Security.User>() { context.Users.FirstOrDefault(u => u.Id == userId) }
}
);
context.SaveChanges();
}
}
}
When I set to publish the project to my azure websites the webservices publish allright but the database doesn't or at least whenever I call the restaurants service with website/api/restaurants which is the route for getting a list of restaurants it says.
{"Message":"An error has occurred."}
My azure database connection string is setup like this:
Data Source=tcp:someidentifier.database.windows.net,1433;Initial Catalog=Database;Integrated Security=False;User ID=Database#someidentifier;Password=xxxxxx;Connect Timeout=30;Encrypt=True
I don't know what is happening and I don't know if azure is actually seeding the database, what did I left out or what could be my mistakes?
First of all, go to your asp.net webconfig and set this value to Off:
<system.web><customErrors mode="Off"/></system.web>
You'll get an informative Yellow Screen of Death and have a chance of figuring out what's actually wrong. If the YoD is unclear, post it on your answer.
To can see exceptions in azure portal go to your web app -> Tools -> Troubleshoot -> Live HTTP traffic, select Analyze.