DestinationAccessException while trying to access destination details using SAP Cloud SDK for JAVA - sap-cloud-sdk

I am trying to retrieve the details of a destination using the APIs provided by SAP Cloud SDK for JAVA. I have added the following annotations to our Spring Boot application:
#ComponentScan(basePackages = {"com.sap.cloud.sdk", "path to my package"}, excludeFilters = {#ComponentScan.Filter(type = CUSTOM, classes = TypeExcludeFilter.class)})
#ServletComponentScan({"com.sap.cloud.sdk", "path to my package"})
#SpringBootApplication()
public class ActionApplication {
public static void main(final String[] args) {
SpringApplication.run(ActionApplication.class, args);
}
}
The SpringBoot application internally uses a JAVA library developed by us. The code for fetching the destination details is present in this library:
public static Destination getDestination() {
Tenant consumerTenant = TenantAccessor.getCurrentTenant();
return TenantAccessor.executeWithTenant(consumerTenant,
() -> DestinationAccessor.getDestination(destinationName));
}
I am able to get the destination details EVERY TIME I run my application locally.
However, when I run my application on cloud, after a few successful attempts, I get the following error:
"com.sap.cloud.sdk.cloudplatform.thread.exception.ThreadContextExecutionException: com.sap.cloud.sdk.cloudplatform.connectivity.exception.DestinationAccessException: Failed to get destination with name 'name_of_the_destination'."
To resolve the issue, I have to re-deploy my Spring Boot application.
Is anything wrong with the implementation? What I understand from the logs is, the threadcontext is not set correctly.

DefaultHttpDestination should be used when building a destination instead of the MockUtil test class. The built destination should also be registered in a DefaultDestinationLoader, and this DefaultDestinationLoader should be prepended in the DestinationAccessor.

Related

Asynchronous HttpClient calls not shown as dependency in Azure App insights for App service automatically

I am new to Azure app insights and want to know why are Asynchronous HttpClient calls not shown as dependency automatically in Azure App insights for App service.
Also, what configuration changes or code changes should I make in ASP.NET project for tracking http dependencies ?
When I refer documentation it says "A dependency is a component that is called by your application. It's typically a service called using HTTP, or a database, or a file system. Application Insights measures the duration of dependency calls, whether its failing or not, along with additional information like name of dependency and so on. You can investigate specific dependency calls, and correlate them to requests and exceptions."
You can use the below example of code to track http dependency automatically
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.DependencyCollector;
using Microsoft.ApplicationInsights.Extensibility;
using System.Net.Http;
using System.Threading.Tasks;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
TelemetryConfiguration configuration = TelemetryConfiguration.CreateDefault();
configuration.InstrumentationKey = "removed";
configuration.TelemetryInitializers.Add(new HttpDependenciesParsingTelemetryInitializer());
var telemetryClient = new TelemetryClient(configuration);
using (InitializeDependencyTracking(configuration))
{
// run app...
telemetryClient.TrackTrace("Hello World!");
using (var httpClient = new HttpClient())
{
// Http dependency is automatically tracked!
httpClient.GetAsync("https://microsoft.com").Wait();
}
}
// before exit, flush the remaining data
telemetryClient.Flush();
// flush is not blocking when not using InMemoryChannel so wait a bit. There is an active issue regarding the need for `Sleep`/`Delay`
// which is tracked here: https://github.com/microsoft/ApplicationInsights-dotnet/issues/407
Task.Delay(5000).Wait();
}
static DependencyTrackingTelemetryModule InitializeDependencyTracking(TelemetryConfiguration configuration)
{
var module = new DependencyTrackingTelemetryModule();
// prevent Correlation Id to be sent to certain endpoints. You may add other domains as needed.
module.ExcludeComponentCorrelationHttpHeadersOnDomains.Add("core.windows.net");
module.ExcludeComponentCorrelationHttpHeadersOnDomains.Add("core.chinacloudapi.cn");
module.ExcludeComponentCorrelationHttpHeadersOnDomains.Add("core.cloudapi.de");
module.ExcludeComponentCorrelationHttpHeadersOnDomains.Add("core.usgovcloudapi.net");
module.ExcludeComponentCorrelationHttpHeadersOnDomains.Add("localhost");
module.ExcludeComponentCorrelationHttpHeadersOnDomains.Add("127.0.0.1");
// enable known dependency tracking, note that in future versions, we will extend this list.
// please check default settings in https://github.com/microsoft/ApplicationInsights-dotnet-server/blob/develop/WEB/Src/DependencyCollector/DependencyCollector/ApplicationInsights.config.install.xdt
module.IncludeDiagnosticSourceActivities.Add("Microsoft.Azure.ServiceBus");
module.IncludeDiagnosticSourceActivities.Add("Microsoft.Azure.EventHubs");
// initialize the module
module.Initialize(configuration);
return module;
}
}
}
NOTE: -
Based on the MSDOC Azure Monitor Application Insights Agent currently supports ASP.NET 4.x only.
For more information please refer the below links:
MS DOC: Application Insights for .NET console applications(Source code) & Automatically dependency tracking
GitHub : LINK1 & LINK2

Use SAP Cloud SDK to integrate with a custom backend service (oData) based on VDM Generator

I followed Alexander Duemont's blog, trying to implement a Java Spring Boot application that consumes Cloud Foundry Destination. The Destination has a custom OData V2 behind it, coming from an On-Premise ERP system. For local dev, when I perform the Maven build, the Integration-Tests module registers failure due to dependency injection
This is part of my Controller
#RestController
#RequestMapping("/resources")
public class ClassificationsController {
private static final Logger logger = CloudLoggerFactory.getLogger(ClassificationsController.class);
private final ClassificationService service;
public ClassificationsController(#Nonnull final ClassificationService service) {
this.service = service;
}
…..
}
The #Nonnull final ClassificationService Service causes org.springframework.beans.factory.UnsatisfiedDependencyException
I cannot use Spring stereotype annotations on generated Service classes (Fluent) to create Beans!
This question is more likely related to Spring Boot configuration.
I'm assuming ClassificationService is an interface and the implementing class exists in the same package.
Please make sure...
... to add the implementing class of ClassificationService to your component scan / test runtime. Feel free to share the integration test code to setup the test environment. Maybe the additional class reference is missing.
... to correctly annotate the respective Application class of your Spring Boot project. For example, assuming your ClassificationService resides in org.example.services.classification, while the rest of your application uses org.example.app. Your basic Application class would look like this, when following the Cloud SDK guide:
#SpringBootApplication
#ComponentScan({"com.sap.cloud.sdk", "org.example.services.classification", "org.example.app"})
#ServletComponentScan({"com.sap.cloud.sdk", "org.example.app"})
public class Application extends SpringBootServletInitializer
{
#Override
protected SpringApplicationBuilder configure( final SpringApplicationBuilder application )
{
return application.sources(Application.class);
}
public static void main( final String[] args )
{
SpringApplication.run(Application.class, args);
}
}
... to annotate the implementing class of ClassificationService with javax.inject.Named. In case you have multiple implementations of the same interface, make sure to give the not-used class a custom (unique) value for the #Named annotation.
... to look for exceptions (Class not found) in the application log during startup.

Why am I getting "A route named 'swagger_docs' is already in the route collection" after I publish my API App?

After publishing my API App I'm getting the yellow error screen of ASP.NET. The error message says "A route named 'swagger_docs' is already in the route collection".
How can I fix this?
This is not related to API Apps per se but more around Web API. What triggers the error is pretty simple:
You publish the API App which is based on Web API.
You discard your project and start working on a new API App based on Web API
You want to publish the new API App instead of the old API App you created at step 1.
You select the API App during "Publish.." and you get the publishing profile of the existing API App we deployed at step 1.
You deploy using Web Deploy and the publishing profile, the new API App on top of the old one.
That will trigger the issue I've explained before. That happens because there are two routes being registered by Swashbuckle when you try to start the app. One of the old one and one of the new one. That's because the old files are still present at the destination.
To solve this, during Web Deploy, click on the Settings tab and then expand the "File Publish Options". There is a checkbox there, called "Remove additional files from destination". This will fix the issue as it will only leave the files you deploy at the destination and not the old ones as well.
Hope it helps.
What if it happens when trying to debug the app locally ?
This happened for me, and the reason was, I renamed my assembly name. So the bin folder had two dlls for the same project with different names which caused this error. Once I deleted the old named dll all is well. Hope this helps.
This happens because You probally are configuring you route in your WebApiConfig class and SwaggerConfig class, as explained below:
WebApiConfig file:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
SwaggerConfig.Register();
}
}
SwaggerConfig file:
using Swashbuckle.Application;
[assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")]
namespace NEOH.Api
{
public class SwaggerConfig
{
public static void Register()
{
What you should do is remove the assembly call on SwaggerConfig file.
It should work.
My Solution & Cause:
I had the same problem when I renamed NamesSpaces,Refactored,etc.
After reading what everyone else did here's what I tried:
Cleaned the Solution in Visual Studio
Cleaned the Bin folder manually
Checked the nameSpace in the Project Properties (copied it just in case) >> Build tab >> Scrolldown to Output and ensure the XML documentation file is correct. You will need this name later.
Opened up: SwaggerConfig.cs >> fixed the name space in here (copy,paste) c.SingleApiVersion("vX","NameSpace")
Scrolled down until I found: GetXmlCommentsPath() copied and pasted the correct name space in the .xml file path.
Ran, smoke tested, finished this post.
My issue was that I was referencing another project that had the Swashbuckle extension.
Here is how I kept both projects without changing the anything in project that was referenced:
Remove the routes created by the project referenced under SwaggerConfig.cs > Register right before GlobalConfiguration.Configuration.EnableSwagger(...).EnableSwaggerUi(...);:
// Clears the previous routes as this solution references another Swagger ASP.NET project which adds the swagger routes.
// Trying to add the Swagger routes more than once will prevent the application from starting
GlobalConfiguration.Configuration.Routes.Clear();
Then, the application will be able to start, but you will see the operations/functions that are in both projects. To remove the operations from the project being referenced...
Create the following class
using Swashbuckle.Swagger;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http.Description;
namespace yournamespace.Models
{
/// <summary>
/// This class allows to manage the Swagger document filters.
/// </summary>
public class SwaggerCustomOperationsFilter : IDocumentFilter
{
/// <summary>
/// Applies the Swagger operation filter to exclude the Swagger operations/functions
/// that are inherited by the other Swagger projects referenced.
/// </summary>
///
/// <param name="p_swaggerDoc">Swagger document</param>
/// <param name="p_schemaRegistry">Swagger schema registry</param>
/// <param name="p_apiExplorer">Api description collection</param>
public void Apply(SwaggerDocument p_swaggerDoc, SchemaRegistry p_schemaRegistry, IApiExplorer p_apiExplorer)
{
IEnumerable<ApiDescription> externalApiDescriptions = p_apiExplorer.ApiDescriptions
.Where(d => d.ActionDescriptor.ControllerDescriptor.ControllerType.Module.Name != GetType().Module.Name);
IEnumerable<int> externalApiDescriptionIndexes = externalApiDescriptions
.Select(d => p_apiExplorer.ApiDescriptions.IndexOf(d))
.OrderByDescending(i => i);
IEnumerable<string> externalPaths = externalApiDescriptions.Select(d => $"/{d.RelativePathSansQueryString()}");
foreach (string path in externalPaths)
{
p_swaggerDoc.paths.Remove(path);
}
foreach (int apiDescriptionIndex in externalApiDescriptionIndexes)
{
p_apiExplorer.ApiDescriptions.RemoveAt(apiDescriptionIndex);
}
}
}
}
And add the following in SwaggerConfig.cs > Register > GlobalConfiguration.Configuration.EnableSwagger(...)
c.DocumentFilter<SwaggerCustomOperationsFilter>();
Alternative cause of this problem:
Seems like a lot of people have this issue resolved by deleting their "bin" and "obj" folders as per the other answers.
However the cause of the issue might be that you are configuring your Swagger Config in a referenced project, as per this comment: https://github.com/domaindrivendev/Swashbuckle/issues/364#issuecomment-226013593
I received this error when one project with Swagger referenced another
project with Swagger. Removing the reference fixed the problem.
This caused me to split some core functionality out into a Third project that both of my API's could reference, rather than them referencing each other.

Azure WebJobs Connection Strings configuration ( AzureWebJobsDashboard?? )

I'm trying to work with Azure Webjobs, I understand the way its works but I don't understand why I need to use two connection strings, one is for the queue for holding the messages but
why there is another one called "AzureWebJobsDashboard" ?
What its purpose?
And where I get this connection string from ?
At the moment I have one Web App and one Webjob at the same solution, I'm experiment only locally ( without publishing anything ), the one thing I got up in the cloud is the Storage account that holds the queue.
I even try to put the same connection string in both places ( AzureWebJobsDashboard,AzureWebJobsStorage) but its throw exception :
"Cannot bind parameter 'log' when using this trigger."
Thank you.
There are two connection strings because the WebJobs SDK writes some logs in the storage account. It gives you the possibility of having one storage account just for data (AzureWebJobsStorage) and the another one for logs (AzureWebJobsDashboard). They can be the same. Also, you need two of them because you can have multiple job hosts using different data accounts but sending logs to the same dashboard.
The error you are getting is not related to the connection strings but to one of the functions in your code. One of them has a log parameter that is not of the right type. Can you share the code?
Okay, anyone coming here looking for an actual answer of "where do I get the ConnectionString from"... here you go.
On the new Azure portal, you should have a Storage Account resource; mine starts with "portalvhds" followed by a bunch of alphanumerics. Click that so see a resource Dashboard on the right, followed immediately by a Settings window. Look for the Keys submenu under General -- click that. The whole connection string is there (actually there are two, Primary and Secondary; I don't currently understand the difference, but let's go with Primary, shall we?).
Copy and paste that in your App.config file on the connectionString attribute of the AzureWebJobsDashboard and AzureWebJobsStorage items. This presumes for your environment you only have one Storage Account, and so you want that same storage to be used for data and logs.
I tried this, and at least the WebJob ran without throwing an error.
#RayHAz - Expanding upon your above answer (thanks)...
I tried this https://learn.microsoft.com/en-us/azure/app-service/webjobs-sdk-get-started
but in .Net Core 2.1, was getting exceptions about how it couldn't find the connection string.
Long story short, I ended up with the following, which worked for me:
appsettings.json, in a .Net Core 2.1 Console app:
{
"ConnectionStrings": {
"AzureWebJobsStorage": "---your Azure storage connection string here---",
"AzureWebJobsDashboard":"---the same connectionstring---"
}
}
... and my Program.cs file...
using System;
using System.IO;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace YourWebJobConsoleAppProjectNamespaceHere
{
public class Program
{
public static IConfiguration Configuration;
static void Main(string[] args)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Path.Combine(AppContext.BaseDirectory))
.AddJsonFile("appsettings.json", true);
Configuration = builder.Build();
var azureWebJobsStorageConnectionString = Configuration.GetConnectionString("AzureWebJobsStorage");
var azureWebJobsDashboardConnectionString = Configuration.GetConnectionString("AzureWebJobsDashboard");
var config = new JobHostConfiguration
{
DashboardConnectionString = azureWebJobsDashboardConnectionString,
StorageConnectionString = azureWebJobsStorageConnectionString
};
var loggerFactory = new LoggerFactory();
config.LoggerFactory = loggerFactory.AddConsole();
var host = new JobHost(config);
host.RunAndBlock();
}
}
}

My custom Windows Service is not writing to my custom Event Log

I have written a custom Windows Service that writes data to a custom Event Log (in the Windows Event Viewer).
For dev'ing the biz logic that the service uses, I created a Windows Form which simulates the Start/Stop methods of the Windows Service.
When executing the biz logic via the Windows Forms, info is successfully written to my custom Event Log. However, when I run the same biz logic from the custom Windows Service, information is failing to be written to the Event Log.
To be clear, I have written a library (.dll) that does all the work that I want my custom service to do - including the create/write to the custom Event Log. My Form application references this library as does my Windows Service.
Thinking the problem is a security issue, I manually set the custom Windows Service to "Log on" as "Administrator", but the service still did not write to the Event Log.
I'm stuck on how to even troubleshoot this problem since I can't debug and step into the code when I run the service (if there is a way to debug a service, please share).
Do you have any ideas as to what could be causing my service to fail to write to the event log?
I use it like this. There can be some typos. Writed it on my phone browser...
public class MyClass
{
private EventLog eventLog = new EventLog();
public void MyClass()
{
if (!System.Diagnostics.EventLog.SourceExists("MyLogSource"))
System.Diagnostics.EventLog.CreateEventSource("MyLogSource", "MyLogSource_Log");
eventLog.Source = "MyLogSource";
eventLog.Log = "MyLogSource_Log";
}
private void MyLogWrite()
{
eventLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
}
}
To debug a running service you need to attach to the process. See here for the steps.
You could also add parameter checking to the Main entry point and have a combination service and console app which would start based on some flag. See this SO post for a good example but here's a snippet:
using System;
using System.ServiceProcess;
namespace WindowsService1
{
static class Program
{
static void Main(string[] args)
{
if (args == null)
{
Console.WriteLine("Starting service...");
ServiceBase.Run(new ServiceBase[] { new Service1() });
}
else
{
Console.WriteLine("Hi, not from service: " + args[0]);
}
}
}
}
The above starts the app in console mode if there any parameters exist and in service mode if there are no parameters. Of course it can be much fancier but that's the gist of the switch.
I discovered why my service wasn't writing to the Event Log.
The problem had nothing to do with any part of the code/security/etc that was attempting to write to the EL. The problem was that my service wasn't successfully collecting the information that is written to the EL - therefore, the service wasn't even attempting to write the log.
Now that I fixed the code that collects the data, data is successfully writing to the event log.
I'm open to having this question closed since the question was amiss to the real problem.

Resources