I am sending some message activity and choice prompts using Hero card as below
firstMessage.inputHint = InputHints.IgnoringInput;
await stepContext.context.sendActivity(firstMessage);
secondMessage = MessageFactory.carousel(boltOnDataMap);
await stepContext.context.sendActivity(secondMessage);
let getNameByType: Object = {
intent: "intent.bundle.get_name_by_type",
"entities": [
{
"entity": "giga",
"type": "ent.mobile_data",
"score": 1,
"canon": "giga"
}
]
};
let promptChoices: CardAction[];
promptChoices = [
{
value: ssoUrl,
type: ActionTypes.OpenUrl,
title: getText(
"show-button:button.txt"
),
},
{
value: getNameByType,
type: ActionTypes.PostBack,
title: getText(
"show-button-2:button2.txt"
),
},
];
const attachment: Partial<Activity> = MessageFactory.attachment(
CardFactory.heroCard(null, null, promptChoices)
);
const promptOptions: PromptOptions = {
prompt: {
...attachment,
inputHint: InputHints.ExpectingInput,
},
choices: ChoiceFactory.toChoices(promptChoices),
};
return await stepContext.prompt(
this.promptsNames.CHOOSE_BOLTONS,
promptOptions
);
Everything is displayed properly on iOS devices but on Android firstMessage does not get displayed. PFA the screenshot below
If I remove the prompt options, firstMessage gets displayed on Android device as well.
I checked this link Waiting method in Bot Framework v4 to confirm I am adding the prompt options correctly and the code looks similar.
Am I doing something wrong, which is causing the text(firstMessage) not be displayed on Android.
I am working on a .net 6 application. I have used Serilog for logging. I have received a request to log the debug logs based on the database settings.
Below is my setting table:
Create table ApplicationSettings
(
Id UNIQUEIDENTIFIER PRIMARY KEY NOT NULL,
Name VARCHAR(500) NOT NULL,
[Value] VARCHAR(200) NOT NULL,
CreatedOn DATETIMEOFFSET,
Active BIT
)
INSERT INTO ApplicationSettings VALUES(NEWID(),'Log Debug Message','true', GETDATE(),1)
SELECT * FROM ApplicationSettings
If "Log Debug Message is true" in above table then only I have to log the debug messages of Serilog or else I don't have to log the debug message.
Here is my appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=Something;Database=SampleDb;Trusted_Connection=True;MultipleActiveResultSets=true;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Serilog": {
"Using": [ "Serilog.Enrichers.ClientInfo", "Serilog.Sinks.MSSqlServer" ],
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Warning",
"System": "Warning",
"System.Net.Http.HttpClient": "Warning"
}
},
"Enrich": [ "FromLogContext", "WithMachineName", "WithClientIp", "WithClientAgent" ],
"WriteTo": [
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "Server=Something;Database=SampleDb;Trusted_Connection=True;MultipleActiveResultSets=true;",
"sinkOptionsSection": {
"tableName": "tblLogs",
"autoCreateSqlTable": true
},
"restrictedToMinimumLevel": "Debug",
"columnOptionsSection": {
"primaryKeyColumnName": "Id",
"addStandardColumns": [ "LogEvent", "SourceContext" ],
"removeStandardColumns": [ "Properties" ],
"additionalColumns": [
{
"ColumnName": "ClientIP",
"PropertyName": "ClientIp",
"DataType": "nvarchar"
}
]
}
}
}
]
}
}
Program.cs
using Serilog;
using Serilog.Events;
var builder = WebApplication.CreateBuilder(args);
#region Configure serilog
builder.Logging.ClearProviders();
IConfigurationRoot configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", false, true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
.Build();
var logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.MinimumLevel.Override("Microsoft", LogEventLevel.Error)
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Error)
.MinimumLevel.Override("Serilog", LogEventLevel.Error)
.Enrich.FromLogContext()
.Enrich.WithClientIp()
.Enrich.WithClientAgent()
.CreateLogger();
Log.Logger = logger;
builder.Logging.AddSerilog(logger);
builder.Host.UseSerilog();
#endregion
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Configure the HTTP request pipeline.
if(app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else if(app.Environment.IsStaging() || app.Environment.IsProduction())
{
app.UseExceptionHandler("/Error");
}
app.UseSerilogRequestLogging();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
HomeController.cs
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
//Here If "Log Debug Message is set to true" in "ApplicationSettings" table
//then only log debug message of Serilog or else don't log.
Log.Debug("Started executing Privacy");
try
{
int a = 1;
int b = 0;
int c = a / b;
}
catch (Exception ex)
{
Log.Error(ex, ex.Message);
}
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
Can anybody help me on this? thanks.
I had a question regarding Teams Microsoft Bot framework. Whenever my bot sends an adaptive card, the top and the bottom of the photo continue to cut off. Inside the adaptive card is the hero card image, it seems I'm unable to resize it to make it fit. I've tried making the image smaller and larger to see if that would fix the issue. Below is a screenshot of the issue I am having.
I'm hoping someone has run into the same issue and if this is fixable or not. Thank you.
Image being used; https://imgur.com/a/hkcSkrJ
public async Task<SendResult> SendAsync(NotificationTeamsAttempt attempt)
{
try
{
if (string.IsNullOrWhiteSpace(attempt.ConversationId))
throw new Exception("Conversation Id is required.");
if (string.IsNullOrWhiteSpace(attempt.ServiceUrl))
throw new Exception("Service Url is required.");
using (var connector = new ConnectorClient(new Uri(attempt.ServiceUrl), _clientId, _clientSecret))
{
var activity = MessageFactory.Text("");
activity.Attachments.Add(attempt.Attachment());
activity.Summary = attempt.Summary();
var response = await connector.Conversations.SendToConversationAsync(attempt.ConversationId, activity);
return new SendResult
{
IsSuccess = true,
DispatchId = response.Id
};
}
}
catch (Exception exception)
{
return new SendResult
{
IsSuccess = false,
Exception = exception
};
}
}
public override Attachment Attachment()
{
var card = new ThumbnailCard
{
Title = "Post submitted for review by " + DraftAuthor,
Subtitle = DraftTitle,
Text = DraftDescription,
Images = new List<CardImage>(),
Buttons = new List<CardAction>()
};
if (!string.IsNullOrWhiteSpace(TeamsUrl))
{
card.Buttons.Add(new CardAction
{
Type = "openUrl",
Title = "Review in Teams",
Value = TeamsUrl.Replace("null", $"%22post%7C{DraftId}%7C{DraftId}%22")
});
}
if (!string.IsNullOrWhiteSpace(SPUrl))
{
card.Buttons.Add(new CardAction
{
Type = "openUrl",
Title = "Review in SharePoint",
Value = $"{SPUrl}?postId={DraftId}&sourceId={DraftId}"
});
}
return card.ToAttachment();
}
Please disregard the black lines I've added. But below you can see where the image is cropping off.
Image of the cropping.
Moving comment to answer -
We are using the below JSON and we get the perfect image without cropping -- { "type": "AdaptiveCard", "body": [ { "type": "TextBlock", "size": "Medium", "weight": "Bolder", "text": "card image test" }, { "type": "Container", "items": [ { "title": "Public test 1", "type": "Image", "url": "https://i.imgur.com/OiJNN03.jpeg" } ] } ], "$schema": "adaptivecards.io/schemas/adaptive-card.json", "version": "1.0" }
I want to create the outlook calendar event with custom value. Because i need to get some value while open the event.
Is this possible to send the custom value while creating the event in outlook add in - calendar event.
const msalConfig = {
auth: {
clientId: CLIENT_ID, // Client Id of the registered application
redirectUri: REDIRECT_URL,
},
};
const graphScopes = ["user.read", "mail.send", "openid", "profile"]; // An array of graph scopes
const msalApplication = new UserAgentApplication(msalConfig);
const options = new MSALAuthenticationProviderOptions(graphScopes);
const authProvider = new ImplicitMSALAuthenticationProvider(
msalApplication,
options
);
const option = {
authProvider, // An instance created from previous step
};
const client = Client.initWithMiddleware(option);
Example Event :
let event = {
"subject": "Let's go for lunch",
"body": {
"contentType": "HTML",
"content": "Does mid month work for you?"
},
"start": {
"dateTime": "2021-08-13T12:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2021-08-13T14:00:00",
"timeZone": "Pacific Standard Time"
},
"location":{
"displayName":"Harry's Bar"
},
"attendees": [
{
"emailAddress": {
"address":"adelev#contoso.onmicrosoft.com",
"name": "Adele Vance"
},
"type": "required"
}
]
};
client.api("/me/events").post(event, (err, res) => {
this.setState({ isLoading: false });
});
I want to pass the custom value while create the event. Is this possible to create the event with custom value.
You can use the Microsoft Graph API to create a Calendar event from custom data.
Imagine I have OrderComponent and CustomerComponent that represent two screens.
In the web version you can create a new customer while in the order screen by launching the customer component inside a popup. So OrderComponent references CustomerComponent directly in the template. So I have to keep both in the same FeaturesModule for this to work.
On the other hand in the Nativescript mobile version, there is no such capability and so the two components/screens are completely independent, so I would like to put them in 2 separate modules: OrderModule, and CustomerModule. And lazy load them so the app launches faster.
In my real application of course it's not just 2 components but several dozens so the mobile app performance is a more pressing issue.
When I try to add a module file with the tns extension like this: order.module.tns.ts, without the corresponding web file, it seems as if the NativeScript bundler is not picking it up, I get the following error:
ERROR: C:\...\src\app\features\orders\orders.module.ts is missing from the TypeScript compilation. Please make sure it is in your tsconfig via the 'files' or 'include' property.
at AngularCompilerPlugin.getCompiledFile (C:\Users\...\node_modules\#ngtools\webpack\src\angular_compiler_plugin.js:753:23)
at plugin.done.then (C:\Users\...\node_modules\#ngtools\webpack\src\loader.js:41:31)
at process._tickCallback (internal/process/next_tick.js:68:7)
# ../$$_lazy_route_resource lazy namespace object ./features/measurement-units/measurement-units.module
# ../node_modules/#angular/core/fesm5/core.js
# ../node_modules/nativescript-angular/platform.js
# ./main.ns.ts
But according to the docs, all I have to do to make a nativescript specific component is add it with the tns extension. Is there another step to make this work for module files?? Help is appreciated
Update
Here is my tsconfig.tns.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "es2015",
"moduleResolution": "node",
"baseUrl": "./",
"paths": {
"~/*": [
"src/*"
],
"*": [
"./node_modules/tns-core-modules/*",
"./node_modules/*"
]
}
}
}
Update 2
My webpack.config.js:
const { join, relative, resolve, sep } = require("path");
const webpack = require("webpack");
const nsWebpack = require("nativescript-dev-webpack");
const nativescriptTarget = require("nativescript-dev-webpack/nativescript-target");
const { nsReplaceBootstrap } = require("nativescript-dev-webpack/transformers/ns-replace-bootstrap");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const { AngularCompilerPlugin } = require("#ngtools/webpack");
module.exports = env => {
// Add your custom Activities, Services and other Android app components here.
const appComponents = [
"tns-core-modules/ui/frame",
"tns-core-modules/ui/frame/activity",
];
const platform = env && (env.android && "android" || env.ios && "ios");
if (!platform) {
throw new Error("You need to provide a target platform!");
}
const projectRoot = __dirname;
// Default destination inside platforms/<platform>/...
const dist = resolve(projectRoot, nsWebpack.getAppPath(platform, projectRoot));
const appResourcesPlatformDir = platform === "android" ? "Android" : "iOS";
const {
// The 'appPath' and 'appResourcesPath' values are fetched from
// the nsconfig.json configuration file
// when bundling with `tns run android|ios --bundle`.
appPath = "app",
appResourcesPath = "app/App_Resources",
// You can provide the following flags when running 'tns run android|ios'
aot, // --env.aot
snapshot, // --env.snapshot
uglify, // --env.uglify
report, // --env.report
sourceMap, // --env.sourceMap
hmr, // --env.hmr,
} = env;
const externals = (env.externals || []).map((e) => { // --env.externals
return new RegExp(e + ".*");
});
const appFullPath = resolve(projectRoot, appPath);
const appResourcesFullPath = resolve(projectRoot, appResourcesPath);
const entryModule = `${nsWebpack.getEntryModule(appFullPath)}.ts`;
const entryPath = `.${sep}${entryModule}`;
const ngCompilerPlugin = new AngularCompilerPlugin({
hostReplacementPaths: nsWebpack.getResolver([platform, "tns"]),
platformTransformers: aot ? [nsReplaceBootstrap(() => ngCompilerPlugin)] : null,
mainPath: resolve(appPath, entryModule),
tsConfigPath: join(__dirname, "tsconfig.tns.json"),
skipCodeGeneration: !aot,
sourceMap: !!sourceMap,
});
const config = {
mode: uglify ? "production" : "development",
context: appFullPath,
externals,
watchOptions: {
ignored: [
appResourcesFullPath,
// Don't watch hidden files
"**/.*",
]
},
target: nativescriptTarget,
entry: {
bundle: entryPath,
},
output: {
pathinfo: false,
path: dist,
libraryTarget: "commonjs2",
filename: "[name].js",
globalObject: "global",
},
resolve: {
extensions: [".ts", ".js", ".scss", ".css"],
// Resolve {N} system modules from tns-core-modules
modules: [
resolve(__dirname, "node_modules/tns-core-modules"),
resolve(__dirname, "node_modules"),
"node_modules/tns-core-modules",
"node_modules",
],
alias: {
'~': appFullPath
},
symlinks: true
},
resolveLoader: {
symlinks: false
},
node: {
// Disable node shims that conflict with NativeScript
"http": false,
"timers": false,
"setImmediate": false,
"fs": "empty",
"__dirname": false,
},
devtool: sourceMap ? "inline-source-map" : "none",
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
name: "vendor",
chunks: "all",
test: (module, chunks) => {
const moduleName = module.nameForCondition ? module.nameForCondition() : '';
return /[\\/]node_modules[\\/]/.test(moduleName) ||
appComponents.some(comp => comp === moduleName);
},
enforce: true,
},
}
},
minimize: !!uglify,
minimizer: [
new UglifyJsPlugin({
parallel: true,
cache: true,
uglifyOptions: {
output: {
comments: false,
},
compress: {
// The Android SBG has problems parsing the output
// when these options are enabled
'collapse_vars': platform !== "android",
sequences: platform !== "android",
}
}
})
],
},
module: {
rules: [
{
test: new RegExp(entryPath),
use: [
// Require all Android app components
platform === "android" && {
loader: "nativescript-dev-webpack/android-app-components-loader",
options: { modules: appComponents }
},
{
loader: "nativescript-dev-webpack/bundle-config-loader",
options: {
angular: true,
loadCss: !snapshot, // load the application css if in debug mode
}
},
].filter(loader => !!loader)
},
{ test: /\.html$|\.xml$/, use: "raw-loader" },
// tns-core-modules reads the app.css and its imports using css-loader
{
test: /[\/|\\]app\.css$/,
use: {
loader: "css-loader",
options: { minimize: false, url: false },
}
},
{
test: /[\/|\\]app\.scss$/,
use: [
{ loader: "css-loader", options: { minimize: false, url: false } },
"sass-loader"
]
},
// Angular components reference css files and their imports using raw-loader
{ test: /\.css$/, exclude: /[\/|\\]app\.css$/, use: "raw-loader" },
{ test: /\.scss$/, exclude: /[\/|\\]app\.scss$/, use: ["raw-loader", "resolve-url-loader", "sass-loader"] },
{
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
use: [
"nativescript-dev-webpack/moduleid-compat-loader",
"#ngtools/webpack",
]
},
// Mark files inside `#angular/core` as using SystemJS style dynamic imports.
// Removing this will cause deprecation warnings to appear.
{
test: /[\/\\]#angular[\/\\]core[\/\\].+\.js$/,
parser: { system: true },
},
],
},
plugins: [
// Define useful constants like TNS_WEBPACK
new webpack.DefinePlugin({
"global.TNS_WEBPACK": "true",
"process": undefined,
}),
// Remove all files from the out dir.
new CleanWebpackPlugin([`${dist}/**/*`]),
// Copy native app resources to out dir.
new CopyWebpackPlugin([
{
from: `${appResourcesFullPath}/${appResourcesPlatformDir}`,
to: `${dist}/App_Resources/${appResourcesPlatformDir}`,
context: projectRoot
},
]),
// Copy assets to out dir. Add your own globs as needed.
new CopyWebpackPlugin([
{ from: "fonts/**" },
{ from: "**/*.jpg" },
{ from: "**/*.png" },
], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }),
// Generate a bundle starter script and activate it in package.json
new nsWebpack.GenerateBundleStarterPlugin([
"./vendor",
"./bundle",
]),
// For instructions on how to set up workers with webpack
// check out https://github.com/nativescript/worker-loader
new NativeScriptWorkerPlugin(),
ngCompilerPlugin,
// Does IPC communication with the {N} CLI to notify events when running in watch mode.
new nsWebpack.WatchStateLoggerPlugin(),
],
};
if (report) {
// Generate report files for bundles content
config.plugins.push(new BundleAnalyzerPlugin({
analyzerMode: "static",
openAnalyzer: false,
generateStatsFile: true,
reportFilename: resolve(projectRoot, "report", `report.html`),
statsFilename: resolve(projectRoot, "report", `stats.json`),
}));
}
if (snapshot) {
config.plugins.push(new nsWebpack.NativeScriptSnapshotPlugin({
chunk: "vendor",
angular: true,
requireModules: [
"reflect-metadata",
"#angular/platform-browser",
"#angular/core",
"#angular/common",
"#angular/router",
"nativescript-angular/platform-static",
"nativescript-angular/router",
],
projectRoot,
webpackConfig: config,
}));
}
if (hmr) {
config.plugins.push(new webpack.HotModuleReplacementPlugin());
}
return config;
};