NET MVC Toggle between Seed Data and Real Data - c#

In Net MVC Core 2, Is there a method in Visual Studio, to Toggle between artificial in-memory Seed data, and real Test Environment sql connection? We are continuously testing between two environments.
This is how to create artificial data from source: "Pro ASP.NET Core MVC 2, Freeman".
To Toggle between Seed Data, I have to remove all this, and then add a real connection string again in Application.json, I am trying to prevent removing/adding code. Currently beginner in MVC, only programming for few months, so trying to learn. Thank you
Create seed data
new Product {
Name = "Kayak", Description = "A boat for one person",
Category = "Watersports", Price = 275 },
new Product {
Name = "Lifejacket",
Description = "Protective and fashionable",
Category = "Watersports", Price = 48.95m },
Then in Startup.cs
public void ConfigureServices(...
services.AddTransient<IProductRepository, EFProductRepository>();
public void Configure(...
SeedData.EnsurePopulated(app);

In order to automatically switch connection string, you'd need to use environment-based configurations. Then, based on your environment variable, your app would read different values.
Check this answer for more details: Setting Environment Variables in .net Core 2.0

The feature, you're looking for, is in EF Core. It's .UseInMemoryDatabase option:
public TestDbContext Context => InMemoryContext();
private TestDbContext InMemoryContext()
{
var options = new DbContextOptionsBuilder<TestDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.EnableSensitiveDataLogging()
.Options;
var context = new TestDbContext(options);
return context;
}
This blog would fill the gaps: https://garywoodfine.com/entity-framework-core-memory-testing-database/

Related

Fetching more than 1000 rows from Domino LDAP server using .NET Core 5 and Novell.Directory.Ldap.NETStandard

I want to fetch all the users from a large location of our Domino LDAP, around ~2000 users altogether. Since .NET Core sadly doesn't have a platform independent LDAP library, I'm using Novell.Directory.Ldap.NETStandard with this POC:
var cn = new Novell.Directory.Ldap.LdapConnection();
cn.Connect("dc.internal", 389);
cn.Bind("user", "pw");
string filter = "location=MyLoc";
var result = cn.Search("", Novell.Directory.Ldap.LdapConnection.ScopeOne, filter, new string[] { Novell.Directory.Ldap.LdapConnection.AllUserAttrs }, typesOnly: false);
int count = 0;
while (result.HasMore()) {
var entry = result.Next();
count++;
Console.WriteLine(entry.Dn);
}
It prints me a lot of entries, but not all. When count = 1000 I got an Size Limit Exceeded exception. I guess this is because I need to use some kind of pagination, so not all entries woult be returned in a single request. There are different questions like this or this one. Both in Java, the .NET Core API seems somehow different.
Approach 1: Try to find out how LdapSearchRequest works in .NET Core
byte[] resumeCookie = null;
LdapMessageQueue queue = null;
var searchReq = new LdapSearchRequest("", LdapConnection.ScopeOne, filter, new string[] { LdapConnection.AllUserAttrs },
LdapSearchConstraints.DerefNever, maxResults: 3000, serverTimeLimit: 0, typesOnly: false, new LdapControl[] { new SimplePagedResultsControl(size: 100, resumeCookie) });
var searchRequest = cn.SendRequest(searchReq, queue);
I'm trying to figure out how the Java examples can be used in .NET Core. This looks good, however I can't figure out how to fetch the LDAP entries. I only get an message id. By looking into the source it seems that I'm on the right way, but they're using MessageAgent which cannot be used outside since it's internal sealed. This is propably the reason why searching for LdapRearchRequest in the source code doesn't give many results.
Approach 2: Using SimplePagedResultsControlHandler
var opts = new SearchOptions("", LdapConnection.ScopeOne, filter, new string[] { LdapConnection.AllUserAttrs });
// For testing purpose: https://github.com/dsbenghe/Novell.Directory.Ldap.NETStandard/issues/163
cn.SearchConstraints.ReferralFollowing = false;
var pageControlHandler = new SimplePagedResultsControlHandler(cn);
var rows = pageControlHandler.SearchWithSimplePaging(opts, pageSize: 100);
This throws a Unavaliable Cricital Extension exception. First I thought that this is an issue of the .NET port, which may doesn't support all the features of the original Java library yet. It seems complete and according to further researches, it looks like to be an LDAP error code. So this must be something which has to be supported by the server, but is not supported by Domino.
I couldn't make at least one of those approachs work, but found another way: Cross platform support for the System.DirectoryServices.Protocols namespace was was added in .NET 5. This was missing for a long time in .NET Core and I guess this is the main reason why libraries like Novell.Directory.Ldap.NETStandard were ported to .NET Core - in times of .NET Core 1.x this was the only way I found to authenticate against LDAP wich works on Linux too.
After having a deeper look into System.DirectoryServices.Protocols, it works well out of the box, even for ~2k users. My basic POC class looks like this:
public class DominoLdapManager {
LdapConnection cn = null;
public DominoLdapManager(string ldapHost, int ldapPort, string ldapBindUser, string ldapBindPassword) {
var server = new LdapDirectoryIdentifier(ldapHost, ldapPort);
var credentials = new NetworkCredential(ldapBindUser, ldapBindPassword);
cn = new LdapConnection(server);
cn.AuthType = AuthType.Basic;
cn.Bind(credentials);
}
public IEnumerable<DominoUser> Search(string filter, string searchBase = "") {
string[] attributes = { "cn", "mail", "companyname", "location" };
var req = new SearchRequest(searchBase, filter, SearchScope.Subtree, attributes);
var resp = (SearchResponse)cn.SendRequest(req);
foreach (SearchResultEntry entry in resp.Entries) {
var user = new DominoUser() {
Name = GetStringAttribute(entry, "cn"),
Mail = GetStringAttribute(entry, "mail"),
Company = GetStringAttribute(entry, "companyname"),
Location = GetStringAttribute(entry, "location")
};
yield return user;
}
yield break;
}
string GetStringAttribute(SearchResultEntry entry, string key) {
if (!entry.Attributes.Contains(key)) {
return string.Empty;
}
string[] rawVal = (string[])entry.Attributes[key].GetValues(typeof(string));
return rawVal[0];
}
}
Example usage:
var ldapManager = new DominoLdapManager("ldap.host", 389, "binduser", "pw");
var users = ldapManager.Search("objectClass=person");
But it's not solved with Novell.Directory.Ldap.NETStandard as the title said
This doesn't solve my problem with the Novell.Directory.Ldap.NETStandard library as the title suggested, yes. But since System.DirectoryServices.Protocols is a official .NET package maintained by Microsoft and the .NET foundation, this seems the better aproach for me. The foundation will take care to keep it maintained and compatible with further .NET releases. When I wrote the question, I was not aware of the fact that Linux support is added now.
Don't get me wrong, I don't want to say that third packages are bad by design - that would be completely wrong. However, when I have the choice between a official package and a third party one, I think it makes sense to prefer the official one. Except there would be a good reason against that - which is not the case here: The official package (which doesn't exist in the past) works better to solve this issue than the third party one.

How to create a direct charge by using a shared customer?

I am attempting to create a direct charge to a connected account from my platform. I have been advised by Stripe support to do this by using a shared customer, however that has just created more issues.
The code itself is very simple, if it worked. It updates the platform customer with the src_... token provided by an iOS app. This works. It then attempts to create a shared customer using the StripeTokenService(). This does not work, despite following the documentation to the letter. The error I receive is:
You provided a customer without specifying a source. The default source of the customer is a source and cannot be shared from existing customers.
I can see no method of providing a source to the shared customer in the Stripe .Net SDK. All I can provide is a Card or BankAccount, neither of which I want to do as the API should remain agnostic of sensitive user information.
What exactly am I doing wrong here?
StripeConfiguration.SetApiKey(Settings.Stripe.SecretKey);
var businessRequestOptions = new StripeRequestOptions { StripeConnectAccountId = businessOwner.StripeAccountId };
var customerService = new StripeCustomerService();
customerService.Update(userDetail.StripeCustomerId, new StripeCustomerUpdateOptions
{
SourceToken = stripeToken // = 'src_...'
});
var tokenService = new StripeTokenService();
// this is the call that generates the error I mentioned above \/ \/
var token = tokenService.Create(new StripeTokenCreateOptions
{
CustomerId = userDetail.StripeCustomerId // = 'cus_...'
}, businessRequestOptions);
// create a direct charge to the business account (taking out application fee)
var chargeService = new StripeChargeService();
var stripeCharge = chargeService.Create(new StripeChargeCreateOptions
{
Amount = Convert.ToInt32(fee),
Currency = currency,
Description = $"Payment to {businessOwner.BusinessName} through Service X",
ApplicationFee = applicationFee,
SourceTokenOrExistingSourceId = token.Id, // use shared customerId here
}, businessRequestOptions);
When using Sources you have to use a different approach which is documented here: https://stripe.com/docs/sources/connect#shared-card-sources
The idea is that you are going to "clone" the Source from the platform to the connected account. This is done using the original_source when creating a new Source. You will then get a new Source object with a different id src_XXXX that you can then charge directly on the connected account.

How to setup Project Backlog in TFS pro grammatically?

I have look around the other post about this Project Backlog, but i want to those missing field in this image here
I need those missing fields like workitem, Title, Assigned To, State, Effort, Business.
I have this code with me right now.
/ Set up default team sprint date and time
var teamConfig = _tfs.GetService<TeamSettingsConfigurationService>();
var css = _tfs.GetService<ICommonStructureService4>();
string rootNodePath = string.Format("\\{0}\\Iteration\\Release 1\\Sprint 1", _selectedTeamProject.Name);
var pathRoot = css.GetNodeFromPath(rootNodePath);
css.SetIterationDates(pathRoot.Uri, DateTime.Now.AddDays(-5), DateTime.Now.AddDays(7));
var configs = teamConfig.GetTeamConfigurationsForUser(new[] { _selectedTeamProject.Uri });
var team = configs.Where(c => c.TeamName == "Demo").FirstOrDefault();
var ts = team.TeamSettings;
ts.BacklogIterationPath = string.Format(#"{0}\Release 1", _selectedTeamProject.Name);
ts.IterationPaths = new string[] { string.Format(#"{0}\Release 1\Sprint 1", _selectedTeamProject.Name), string.Format(#"{0}\Release 1\Sprint 2", _selectedTeamProject.Name) };
var tfv = new TeamFieldValue();
tfv.IncludeChildren = true;
tfv.Value = _selectedTeamProject.Name;
ts.TeamFieldValues = new []{tfv};
teamConfig.SetTeamSettings(team.TeamId, ts);
According to your screenshot, seems you are using the Work item Summary web part. After the upgrade to TFS2018, your TFS SharePoint sites will display, but all integration functionality is disabled.
The official recommended way is using TFS Dashboards for a better way to create dashboards. From that it's more easy to track/display the fields in a work item.
You could directly use some 3-party Work Item widget such as this one which also provides a summary for a selected work item.
To get or update work items such as product backlog fields pro grammatically, you could use Rest API-- Get a list of work items to handle this. It will also return all related fields name and value. Which also include a C# (GetWorkItemsByIDs method) sample code. About how to customize a dashboard in sharepoint, please take a look at this thread.

Retrieving SQL Generated by Entity Framework Core

I'm trying to retrieve the raw SQL generated by Entity Framework for the following LINQ query:
pagedItemResults = from firstItem in dbData.Accession
join secondItem in pagedRowNumberResults
on firstItem.AccessionNumber equals secondItem
select new PaginationResultRow
{
Number = firstItem.AccessionNumber,
ID = firstItem.AccessionId,
Name = firstItem.AcquisitionType.Name,
Description = firstItem.Description
};
Although it may be extremely simple and similar to the other answers already out there for previous versions of EF, I've had no luck and found nothing online.. any ideas??
You can turn on logging by implementing ILoggerProvider. See details in documentation.
You only need to register the logger with a single context instance. Once you have registered it, it will be used for all other instances of the context in the same AppDomain.
using (var db = new BloggingContext())
{
var serviceProvider = db.GetInfrastructure<IServiceProvider>();
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
loggerFactory.AddProvider(new MyLoggerProvider());
}
You can also define categories what you want to log.
private static string[] _categories =
{
typeof(Microsoft.Data.Entity.Storage.Internal.RelationalCommandBuilderFactory).FullName,
typeof(Microsoft.Data.Entity.Storage.Internal.SqlServerConnection).FullName
};
You can log tsql generated to output window by :
Microsoft.Extensions.Logging.Debug
First, get it from Nuget, then in your context, you must define a LoggerFactory.
After that, use it in OnConfiguring in your context.
public static readonly Microsoft.Extensions.Logging.LoggerFactory _loggerFactory =
new LoggerFactory(new[] {
new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider()
});
optionsBuilder.UseLoggerFactory(_loggerFactory);
I really like MiniProfiler, see http://miniprofiler.com/. Short of something like this, I would say you'd have to use a profiler on the actual database.

VersionOne API Client not recognizing asset types?

I am running into a problem with the VersionOneAPIClient in that it will not recognize anything I give it ass an asset type. I understand the Attribute definitions probably don't make any sense but I've been trying pretty much everything. My end goal would be to query TeamRooms and get team names from all the teams in the team room.
It's my understanding from the documentation on asset types and how to query that this should work but that's what we all say.
I am using:
C# ASP.NET, VersionOneAPIClient 15.0.0.0
Strings I have tried:
TeamRoom
Task
Scope
Project
public bool APIgetTeams()
{
IAssetType teamroomType = services.Meta.GetAssetType("Task");
Query query = new Query(teamroomType);
IAttributeDefinition teamAttribute = teamroomType.GetAttributeDefinition("Children:Room.Team.Name");
query.Selection.Add(teamAttribute);
IAttributeDefinition scheduleAttribute = teamroomType.GetAttributeDefinition("Children:Scope.Room.Schedule.Name");
query.Selection.Add(scheduleAttribute);
query.Find = new QueryFind(scheduleName, new AttributeSelection(scheduleAttribute));
query.Paging.PageSize = 1;
query.Paging.PageSize = 0;
teamRoomAsset = (Asset)services.Retrieve(query).Assets.ToArray().GetValue(0);
return true;
}
My definition of services and the connector:
public static V1Connector connector = V1Connector
.WithInstanceUrl("http://versionone.cscinfo.com/VersionOneProd/")
.WithUserAgentHeader("New Dashboard?", "1.0")
.WithWindowsIntegrated()
.Build();
public IServices services = new Services(connector);
And these are my Errors / Stack Traces:
The error is likely simple and right in my face but I can't figure it out.
You have a couple of things going on here. I will address your statement "My end goal would be to query TeamRooms and get team names from all the teams in the team room."
Here is a working chunk of code that reads all of your TeamRooms and prints the name of the Team Room and the Team Name. Once you get this working on your machine, attempt to do the paging. Add filtering incrementally to keep the debug cycles low.
static void Main(string[] args)
{
V1Connector connector = V1Connector
.WithInstanceUrl("https://www.MyV1INstance")
.WithUserAgentHeader("HappyApp", "0.1")
.WithUsernameAndPassword("login", "pwd")
.Build();
IServices services = new Services(connector);
IAssetType trType = services.Meta.GetAssetType("TeamRoom");
Query query = new Query(trType);
IAttributeDefinition teamAttribute = trType.GetAttributeDefinition("Team.Name");
IAttributeDefinition nameAttribute = trType.GetAttributeDefinition("Name");
query.Selection.Add(teamAttribute);
query.Selection.Add(nameAttribute);
QueryResult result = services.Retrieve(query);
Asset teamRooms = result.Assets[0];
foreach (Asset story in result.Assets)
{
Console.WriteLine(story.Oid.Token);
Console.WriteLine(story.GetAttribute(teamAttribute).Value);
Console.WriteLine(story.GetAttribute(nameAttribute).Value);
Console.WriteLine();
}
Addendum
I just realized that you were using WithWindowsIntegrated() instead of WithUsernameAndPassword().
Just change that in my sample but then confirm that you are logged into the machine as a Member that is already setup in VersionOne. The windows int auth is trusting IIS' decision to trust you but then immediately after allowing auth, you have to have an active Member account in VersionOne to have access to VersionOne assets.

Categories