Calling InstallPackageAsync with my custom FolderNuGetProject does not install files - nuget

When using the v6.3 Nuget.Packaging and NuGet.PackageManagement libaries, I am unable to install packages like I can when using v.4.0 equivalent.
It seems to be releated to my PluginProject.InstallPackageAsync override, v6 throws a null refernce exception but not with v4. Not calling the base.InstallPackagesAsync fails to install any packages in my folder so im sure its key.
// Class is derived from FolderNuGetProject and method overidden
public override async Task<bool> InstallPackageAsync(PackageIdentity packageIdentity, DownloadResourceResult downloadResourceResult,
INuGetProjectContext nuGetProjectContext, CancellationToken token)
{
var result = await base.InstallPackageAsync(packageIdentity, downloadResourceResult, nuGetProjectContext, token);
await _packagesConfigProject.InstallPackageAsync(packageIdentity, downloadResourceResult, nuGetProjectContext, token);
return result;
}
Even when using the FolderNuGetProject directly, it throws - so I have found the source of the error need to debug the source to understand why... nuGetProjectContext.PackageExtractionContext is null.
Detail
I writing an app which has plugins downloadable from nuget, which can then be dynamically loaded into my application - similair to this interesting talk.
I derive my class from the NuGet.ProjectManagement.FolderNuGetProject, however files are not installed after calling NuGetPackageManager.InstallPackageAsync with my custom folder project, only packages.config is updated per below:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Unified.Mqtt.Pattern" version="1.0.3" targetFramework="netstandard2.0" />
</packages>
But no files in the directory other than that:
PS C:\ProgramData\unified.msp> dir
Directory: C:\ProgramData\unified.msp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 07/08/2022 11:07 156 packages.config
The Project class is below:
public class PluginProject : FolderNuGetProject
{
private readonly PackagesConfigNuGetProject packagesConfigProject;
public PluginProject(string root) : base(root)
{
this.packagesConfigProject = new PackagesConfigNuGetProject(root, new Dictionary<string, object>()
{
{ "TargetFramework", NuGetFramework.AnyFramework },
{ "Name", "My.Package.Installer" }
});
}
public override Task<IEnumerable<PackageReference>> GetInstalledPackagesAsync(CancellationToken cancellationToken)
{
return this.packagesConfigProject.GetInstalledPackagesAsync(cancellationToken);
}
public override Task<bool> InstallPackageAsync(PackageIdentity packageIdentity, DownloadResourceResult downloadResourceResult,
INuGetProjectContext nuGetProjectContext, CancellationToken token)
{
// THIS LINE THROWS NULL REFERENCE WITH v6, BUT NOT v4
var result = await DeletePackage(packageIdentity, nuGetProjectContext, token);
await
packagesConfigProject.UninstallPackageAsync(packageIdentity, nuGetProjectContext, token);
return result;
}
}
And the overall plugin manager is below (which scaffolds everything together into the NuGetPackangeManager method calls. It does list installed packages, and can install (ableit without the actual file contents):
public class NugetPluginManager
{
private readonly IOptions<NugetPluginManagerSettings> settings;
private readonly LoggerAdapter logger;
public NugetPluginManager(IOptions<NugetPluginManagerSettings> settings, ILogger<NugetPluginManager> logger)
{
this.settings = settings;
this.logger = new LoggerAdapter(logger);
}
private static (SourceRepository Repository, List<Lazy<INuGetResourceProvider>> Providers) GetRepository(string repositoryUrl)
{
var providers = new List<Lazy<INuGetResourceProvider>>();
providers.AddRange(Repository.Provider.GetCoreV3());
var packageSource = new PackageSource(repositoryUrl);
var repository = new SourceRepository(packageSource, providers);
if(packageSource.SourceUri.Scheme != Uri.UriSchemeHttps)
throw new ArgumentException($"{repositoryUrl} is not https.", nameof(repositoryUrl));
return (repository, providers);
}
public async Task<IEnumerable<PackageReference>> GetInstalledPackages(CancellationToken cancellationToken = default)
{
var commonApplicationDataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
var rootAppPath = Path.Combine(commonApplicationDataPath, "unified.msp");
var packagesPath = Path.Combine(rootAppPath, "packages");
var project = new PluginProject(rootAppPath);
return await project.GetInstalledPackagesAsync(cancellationToken);
}
public async Task Install(string repositoryUrl, string packageName, string version, bool includeDependencies,
bool includePreRelease, CancellationToken cancellationToken = default)
{
var (repository, providers) = GetRepository(repositoryUrl);
var commonApplicationDataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
var rootAppPath = Path.Combine(commonApplicationDataPath, "unified.msp");
var packagesPath = Path.Combine(rootAppPath, "packages");
var project = new PluginProject(rootAppPath);
var defaultSettings = Settings.LoadDefaultSettings(rootAppPath, null, new XPlatMachineWideSetting());
// Create the package manager - TODO: https://github.com/NuGet/Home/issues/8479
#pragma warning disable CS0618 // Type or member is obsolete
var repositoryProvider = new SourceRepositoryProvider(defaultSettings, providers);
#pragma warning restore CS0618 // Type or member is obsolete
var packageManager = new NuGetPackageManager(repositoryProvider, defaultSettings, packagesPath)
{
PackagesFolderNuGetProject = project
};
var dependencyBehaviour = includeDependencies ? DependencyBehavior.Lowest : DependencyBehavior.Ignore;
var resolutionContext =
new ResolutionContext(dependencyBehaviour, includePreRelease, false, VersionConstraints.None);
var projectContext = new EmptyNuGetProjectContext();
await packageManager.InstallPackageAsync(
packageManager.PackagesFolderNuGetProject,
new PackageIdentity(packageName, NuGetVersion.Parse(version)),
resolutionContext,
projectContext,
repository,
Array.Empty<SourceRepository>(),
cancellationToken);
}
}

Stepping into the source code with Resharper the error the PackageExtractionContext was missing! Adding below resolved this:
var settings = Settings.LoadDefaultSettings(root: null);
var projectContext = new EmptyNuGetProjectContext()
{
PackageExtractionContext = new PackageExtractionContext(
PackageSaveMode.Defaultv3,
XmlDocFileSaveMode.Skip,
ClientPolicyContext.GetClientPolicy(settings, this.logger),
this.logger)
};
await packageManager.InstallPackageAsync(
packageManager.PackagesFolderNuGetProject,
new PackageIdentity(packageId, NuGetVersion.Parse(packageVersion)),
new ResolutionContext(DependencyBehavior.Ignore, false, false, VersionConstraints.None),
projectContext,
_repository,
new SourceRepository[] { },
CancellationToken.None);

nuGetProjectContext.PackageExtractionContext is null.
This is obviously because the package is missing in the first place! :3
When using the v6.3 Nuget.Packaging and NuGet.PackageManagement libaries, I am unable to install packages like I can when using v.4.0 equivalent.
Of course, you're gonna have to install them manually in the code you provided in your answer!
Tip: Since you're using a newer version, it is highly possible the PackageExtractionContext package is no longer compatible with the new version, and have to be installed by you manually.
This applies for many libraries and extensions with its packages.

Related

Is there any efficient way to get the latest commit of a particular branch using this package?

This question is the continuation of this question, As requested I have raised this as a separate question.
How to check whether a commit is present in a Branch in Azure Dev Ops?
Is there any efficient way to get the latest commit of a particular branch using this package?
The below is a C# demo, it should achieve your requirement:
using Microsoft.TeamFoundation.SourceControl.WebApi;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.WebApi;
using System;
using System.Collections.Generic;
using System.Linq;
namespace CheckWhetherCommitExistInCurrentBranch
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
Uri orgUrl = new Uri("https://dev.azure.com/xxx/"); // Organization URL
string project = "xxx";
string repository = "xxx";
String personalAccessToken = "xxx";
string branch_name = "xxx";
var commitref = GetLastestCommit(orgUrl, personalAccessToken, project, repository, branch_name);
Console.WriteLine("The latest commit id is: "+commitref.CommitId);
}
//get lastest commit
public static GitCommitRef GetLastestCommit(Uri orgUrl, string personalAccessToken, string project, string repoId, string branchName)
{
List<string> branches = new List<string>();
VssConnection connection = new VssConnection(orgUrl, new VssBasicCredential(string.Empty, personalAccessToken));
GitHttpClient gitClient = connection.GetClient<GitHttpClient>();
var commit = gitClient.GetCommitsAsync(project: project, repositoryId: repoId, new GitQueryCommitsCriteria()
{
ItemVersion = new GitVersionDescriptor()
{
Version = branchName,
VersionType = GitVersionType.Branch
},
Top = 1
}).Result.FirstOrDefault();
return commit;
}
}
}
Works Successfully on my side:

Upgrade to CSLA 6: ConnectionManager problem

we are trying to upgrade to CSLA 6.
now, we are getting a message:
"ConnectionManager is obsolete, use dependency injection ... use ApplicationContext.LocalContext"
for this code:
using (var ctx = ConnectionManager<OracleConnection>.GetManager("dbEndpoint", true))
We've tried this code snippet but all connections is NULL.
Could you please help us to correctly get Connection?
var services = new ServiceCollection();
services.AddCsla();
var provider = services.BuildServiceProvider();
DataPortalFactory = provider.GetRequiredService<IDataPortalFactory>();
var appContext = provider.GetRequiredService<Csla.ApplicationContext>();
var conn1 = appContext.LocalContext.GetValueOrNull("dbEndpoint");
var conn2 = appContext.LocalContext.GetValueOrNull("__db:default-dbEndpoint");
var conn3 = appContext.LocalContext["dbEndpoint"];
var conn4 = appContext.LocalContext["__db:default-dbEndpoint"];
another experiment:
....
var CONNECTION_ORACLE = new OracleConnection(ConfigurationManager.ConnectionStrings["dbEndpoint"].ConnectionString);
services.AddScoped<IDbConnection>(o => CONNECTION_ORACLE);
....
var provider = services.BuildServiceProvider();
...
var connectionResolved = provider.GetRequiredService<IDbConnection>();
appContext.LocalContext.Add("dbEndpoint", connectionResolved);
then connection is not null;
and inside of Factory is successfully resolved by DI:
public DocFactory(ApplicationContext appContext, IDbConnection connection) : base(
appContext)
{
_connection = connection;
}
then
[Fetch]
public Doc_Fetch(DocCriteria criteria)
{
bool cancel = false;
OnFetching(criteria, ref cancel);
if (cancel) return null;
Doc item = null;
OracleConnection connection = _connection as OracleConnection;
connection is Closed (but NOT null!!). it's possible to open it but if close it, somebody else consuming it will face with a problem or child objects also will face problem with closed connection.
so, making ConnectionManager as Obsolete may be not so obvious way to go. But ConnectionManager was very useful for counting open connection, supporting transactions etc
Could you please provide a workaround for it.
more attempts:
var connectionString =
ConfigurationManager.ConnectionStrings["dbEndpoint"].ConnectionString;
..
appContext.ClientContext.Add("DBConnectionString", connectionString );
...
Factory
using (var connection = new OracleConnection(ApplicationContext.ClientContext["DBConnectionString"].ToString()))
{
connection.Open();
Your DAL should require that a database connection be injected.
public class MyDal : IDisposable
{
public MyDal(OracleConnection connection)
{
Connection = connection;
}
private OracleConnection Connection { get; set; }
public MyData GetData()
{
// use Connection to get the data
return data;
}
public void Dispose()
{
Connection.Dispose();
}
}
Then in the app server startup code, register your DAL type(s) and also register your connection type.
services.AddScoped(typeof(OracleConnection), () =>
{
// initialize the connection here
return connection;
});
services.AddScoped<MyDal>();
Then, in your data portal operation method (such as create, fetch, etc.), inject your DAL:
[Fetch]
private void Fetch([Inject] MyDal dal)
{
var data = dal.GetData();
}

Error: System.Net.Http.HttpRequestException: Response status code does not indicate success: 405 (Method Not Allowed)

I am getting following exception when calling an Asp.NET Core 3.1 web api from a Blazor app.
But same code works great from visual studio debugging
Response status code does not indicate success: 405 (Method Not Allowed).
at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
at Microsoft.AspNetCore.Components.HttpClientJsonExtensions.SendJsonAsync[T](HttpClient httpClient, HttpMethod method, String requestUri, Object content)*
UI Code:
public async Task<bool> UpdateCOAValue(COALookUps dataItem)
{
bool result = false;
try
{
bool response = await _httpClient.SendJsonAsync<bool>(HttpMethod.Put, string.Format(#_webApi.WebAPIUrl, "update"), dataItem);
result = await Task.FromResult(response);
}
catch (Exception ex)
{
Log.Error("Error: {0}", ex);
}
return result;
}
Web API Controller Method:
[HttpPut("update")]
public bool UpdateCOAEntry([FromBody]COALookups value)
{
try
{
List<SqlParameter> lstSQLParams = new List<SqlParameter>();
SqlParameter paramCOALookUpID = new SqlParameter();
//other code
dbManager.Update("UpdateCOALookUp", CommandType.StoredProcedure, lstSQLParams.ToArray());
}
catch (Exception ex)
{
Log.Error("Error: {0}", ex);
return false;
}
return true;
}
Web API Controllers syntax:
[Route("api/[controller]")]
[ApiController]
public class COAController : ControllerBase
{
}
Here is what worked for me. (this is a workaround), will have to redo this after each release. Please post if anyone has a better solution.
Open WebDav Authoring Rules and then select Disable WebDAV option
present on the right bar.
Select Modules, find the WebDAV Module and remove it.
Select HandlerMapping, find the WebDAVHandler and remove it.
I found this solution working than changing any settings in IIS
In ConfigureServices method add following
var handler = new HttpClientHandler()
{
UseDefaultCredentials = false,
Credentials = System.Net.CredentialCache.DefaultCredentials,
AllowAutoRedirect = true
};
services.AddSingleton(sp =>
new HttpClient(handler)
{
BaseAddress = new Uri(Configuration["WebAPI:BaseUrl"])
});

Error handling Web Api .net core and Repository Pattern

I have question about web api and Repository may be its a duplicate question.
but i tried to search on it and i did not get any satisfactory answer.
In my Repository i am getting data with the help of httpclient.
My question is that i can get an error inside my response or i can get required json data which i can map to my product class.I am returning IEnumerable.
1) If i get an error how can i bubble it up to controller and display an error to user.
2) Return the MessageResponse instead of IEnumerable and handle it inside the controller.
What is the best way.
enter code here
public interface IProduct{
Task<IEnumerable<Product>> All();
}
public class Product:IProduct
{
public async Task<IEnumerable<Product>> All(){
var ResponseMessage=//some response.
}
}
You could customize a ApiException which is used to get the error message of the response, and call the UseExceptionHandler in your startup.cs ,refer to the following :
ProductRep
public class ProductRep : IProduct
{
private readonly HttpClient _client;
public ProductRep(HttpClient client)
{
_client = client;
}
public async Task<IEnumerable<Product>> All()
{
List<Product> productlist = new List<Product>();
var response = await _client.GetAsync("https://localhost:44357/api/values/GetProducts");
string apiResponse = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode == false)
{
JObject message = JObject.Parse(apiResponse);
var value = message.GetValue("error").ToString();
throw new ApiException(value);
}
productlist = JsonConvert.DeserializeObject<List<Product>>(apiResponse);
return productlist;
}
public class ApiException : Exception
{
public ApiException(string message): base(message)
{ }
}
}
Startup.cs
app.UseExceptionHandler(a => a.Run(async context =>
{
var feature = context.Features.Get<IExceptionHandlerPathFeature>();
var exception = feature.Error;
var result = JsonConvert.SerializeObject(new { error = exception.Message });
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(result);
}));

Using Autofac with webapi and mvc5.1 not working for webapi

I have a project using both mvc and webapi.
It's a Membership Reboot application so I have taken the example single application project and have slightly modified it to suit.
The DI works ok for controllers however when I try to call a webapi controller I keep getting an error
Make sure that the controller has a parameterless public constructor.
Is there something else I need to do for using autofac with webapi?
This is the code from my startup.cs
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "External",
AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Passive
});
ConfigureMembershipReboot(app);
}
private static void ConfigureMembershipReboot(IAppBuilder app)
{
System.Data.Entity.Database.SetInitializer(new System.Data.Entity.MigrateDatabaseToLatestVersion<DefaultMembershipRebootDatabase, BrockAllen.MembershipReboot.Ef.Migrations.Configuration>());
//System.Data.Entity.Database.SetInitializer(new System.Data.Entity.CreateDatabaseIfNotExists<DefaultMembershipRebootDatabase>());
var cookieOptions = new CookieAuthenticationOptions
{
AuthenticationType = MembershipRebootOwinConstants.AuthenticationType
};
BuildAutofacContainer(app, cookieOptions.AuthenticationType);
app.UseMembershipReboot(cookieOptions);
}
private static void BuildAutofacContainer(IAppBuilder app, string authType)
{
var builder = new ContainerBuilder();
var config = CreateMembershipRebootConfiguration(app);
builder.RegisterInstance(config).As<MembershipRebootConfiguration>();
builder.RegisterType<DefaultUserAccountRepository>()
.As<IUserAccountRepository>()
.As<IUserAccountQuery>()
.InstancePerLifetimeScope();
builder.RegisterType<UserAccountService>().OnActivating(e =>
{
var owin = e.Context.Resolve<IOwinContext>();
var debugging = false;
#if DEBUG
debugging = true;
#endif
e.Instance.ConfigureTwoFactorAuthenticationCookies(owin.Environment, debugging);
})
.AsSelf()
.InstancePerLifetimeScope();
builder.Register(ctx =>
{
var owin = ctx.Resolve<IOwinContext>();
return new OwinAuthenticationService(authType, ctx.Resolve<UserAccountService>(), owin.Environment);
})
.As<AuthenticationService>()
.InstancePerLifetimeScope();
builder.Register(ctx=>HttpContext.Current.GetOwinContext()).As<IOwinContext>();
builder.RegisterControllers(typeof(Startup).Assembly);
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
var container = builder.Build();
System.Web.Mvc.DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
It was a 1 liner :)
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);