When you use EventId
in .NET logs, both the Id
(an integer) and Name
are sent to Application Insights as part of customDimensions
. However, the EventId.Id
is stored as a string, which affects how you can filter it.
The Application Insights UI filter panel only supports string operations like equals
or contains
. You can’t use greater than
or less than
filters directly in the UI.
To filter numerically, use the Logs (Analytics) tab with Kusto Query Language (KQL):
This converts the string to an integer so you can filter properly.
Use numeric ranges for EventId
to categorize logs (e.g., 1000–1999 = Auth, 2000–2999 = Payments) and filter easily with KQL.
Tracking custom events with TrackEvent()
in Azure Application Insights helps you monitor how users interact with your app. However, to obtain meaningful data, it's essential to name your events clearly and consistently.
Here are some best practices:
Write event names using a Verb-Noun format like UserLoggedIn
, FileDownloaded
, or OrderSubmitted
. This makes them easy to understand.
Use PascalCase (each word starts with a capital letter), and avoid:
User Logged In
)User-Logged-In
)user_logged_in
)Use: UserLoggedIn
Keep user IDs, file names, or other changing values out of the event name.
Instead, put that info in custom properties or metrics.
Follow the same naming style across your app. This makes it easier to search and analyze data later.
If similar actions happen in different contexts, make your event name more specific:ContactFormSubmitted
vs. FeedbackFormSubmitted
Use a naming template like:<Action><Entity>[<Qualifier>]
Example: AddedItemToCart
A clean, consistent naming strategy makes your telemetry easier to work with, both now and in the future.
To make your ASP.NET Core services easy to test and maintain, follow this proven pattern. The example below demonstrates how to register a service and configure an HttpClient
with custom handlers, while keeping the design flexible for unit testing.
Register your service interface and implementation as a singleton (or other lifetime as needed). This keeps the service replaceable in tests:
services.AddSingleton<IMyService, MyService>();
Tip: Use TryAdd for safe registration in reusable code
If your registration code is part of a shared library or package, use TryAdd
to avoid overriding existing registrations accidentally:
services.TryAddSingleton<IMyService, MyService>();
Use a named HttpClient to add retry and logging handlers. These handlers improve reliability and diagnostics:
services.AddHttpClient(nameof(MyService)) .AddHttpMessageHandler(s => new RetryHandler(s)) .AddHttpMessageHandler(s => new LoggingHandler(s));
You can call AddMemoryCache()
without worry — it internally prevents duplicates:
services.AddMemoryCache();
public static class ServiceCollectionExtensions { public static IServiceCollection AddMyClientServices(this IServiceCollection services) { ArgumentNullException.ThrowIfNull(services); services.AddMemoryCache(); services.TryAddSingleton<IMyService, MyService>(); services.AddHttpClient(nameof(MyService)) .AddHttpMessageHandler(s => new RetryHandler(s)) .AddHttpMessageHandler(s => new LoggingHandler(s)); return services; } }
Why This Matters
Using this approach ensures your ASP.NET Core apps are easier to maintain, test, and extend.
When building tree structures in React, you might see this warning:
"Encountered two children with the same key..."
This usually happens when your component is rendering a list or tree and uses the same key
value for multiple items. React requires that keys be unique among siblings to correctly track changes.
In some apps, a tree of items is built using IDs like id
, targetId
, and parentId
. A common mistake is using a field like targetId
as the unique key — but if that field isn't truly unique, React throws an error.
Also, when building the tree structure, developers often assume that parentId
matches a node’s id
, but sometimes it actually matches others like targetId
— and since targetId
isn't unique, that causes lookup problems.
Here’s how to correctly build the tree and avoid duplicate keys:
id
as the unique key — it's meant to be unique and stable.id
.targetId
to nodes — since targetId
isn't unique, store an array of nodes per targetId
.parentId
to the corresponding targetId
, and attach the node to all matches (if multiple).Here’s a simplified version of the corrected tree builder:
function buildTree(nodes) { const updatedNodes = nodes.map(node => ({ ...node, id: String(node.id), targetId: String(node.targetId), parentId: String(node.parentId), children: [], })); const targetIdToNodes = {}; updatedNodes.forEach(node => { if (!targetIdToNodes[node.targetId]) { targetIdToNodes[node.targetId] = []; } targetIdToNodes[node.targetId].push(node); }); const rootNodes = []; updatedNodes.forEach(node => { if (node.parentId === '0') { rootNodes.push(node); } else { const parents = targetIdToNodes[node.parentId]; if (parents) { parents.forEach(parent => { parent.children.push(node); }); } } }); return rootNodes; }
In your React rendering, always use node.id
for the key
:
<TreeNode key={node.id} node={node} />
Always make sure your keys in React are unique and stable. And when building a tree, know what your parentId
is pointing to — it can make or break your structure.
JSX may look like HTML, but it’s actually JavaScript. When used correctly, it brings power and clarity to React development.
{}
for JavaScript expressions.className
instead of class
.<img />
.<div>
or <>
.Example:
function Greeting() { return <h1>Hello, world!</h1>; }
class
instead of className
.When using ref
in React, especially with forwardRef
, it's important to understand how ref
works — and how it doesn't.
You might see this warning in your console:
ref
is not a prop. Trying to access it will result inundefined
being returned...
This usually happens when you try to declare ref
in your component's propTypes
or access it like a normal prop (props.ref
). But ref
is a special prop in React. It doesn't behave like other props.
ref
When using forwardRef
, React gives the ref
as the second argument of your function. Here's what that looks like:
const MyComponent = forwardRef(function MyComponent(props, ref) { // use ref directly });
Don't try to access ref
through props.ref
. That won't work.
MyComponent.propTypes = { // This will trigger a warning! ref: PropTypes.any, };
React doesn't pass ref
through the normal props
object, so it shouldn’t be validated with propTypes
.
ref
only via the second argument in forwardRef
.ref
from propTypes
.This will prevent the warning and adhere to React best practices.
If you're using TinyMCE in a React app and want to provide users with a way to remove all data-*
attributes from their content, you can create a custom toolbar button to do just that.
data-*
attributes are often added by frameworks, plugins, or tracking tools. In some cases, you might want to remove these before saving or publishing content, especially for clean, production-ready HTML.
You can use TinyMCE’s setup
function to add a custom button with a mop-like icon to your toolbar. Here's how:
import { Editor } from '@tinymce/tinymce-react'; function MyEditor({ content, contentChange, onEditorInit }) { return ( <Editor value={content} onEditorChange={(newValue) => contentChange(newValue)} onInit={onEditorInit} init={{ height: 500, menubar: false, plugins: 'code', toolbar: 'undo redo | mopCleaner | bold italic underline | code', setup: (editor) => { editor.ui.registry.addIcon('mopCleanerIcon', ` <svg width="24" height="24" viewBox="0 0 24 24"> <path d="M12 2v14" stroke="currentColor" stroke-width="2"/> <path d="M8 16h8l1 4H7l1-4z" fill="currentColor"/> </svg> `); editor.ui.registry.addButton('mopCleaner', { icon: 'mopCleanerIcon', tooltip: 'Remove all data-* attributes', onAction: () => { const currentContent = editor.getContent(); const cleanedContent = currentContent.replace(/\sdata-[\w-]+="[^"]*"/g, ''); editor.setContent(cleanedContent); }, }); }, }} /> ); }
data-something="value"
.data-*
attributes are in a single tag.To support edge cases, such as attributes with single quotes or no values, you can enhance the regex as needed.
TinyMCE is a popular rich text editor used to add content-editing capabilities to web apps. When working with React, TinyMCE provides an official wrapper that makes integration quick and easy.
Here’s how to set it up in a React project:
Use npm:
npm install @tinymce/tinymce-react
Import the component and render it:
import { Editor } from '@tinymce/tinymce-react'; function MyEditor() { return ( <Editor initialValue="<p>Start typing...</p>" init={{ height: 300, menubar: false, plugins: 'link image code', toolbar: 'undo redo | formatselect | bold italic | link image | code', }} /> ); }
This will render a fully functional rich text editor inside your React component.
You can capture changes to the editor content like this:
<Editor onEditorChange={(newContent) => { console.log(newContent); // Save or process the content here }} />
TinyMCE is highly customizable with plugins, themes, and custom toolbars.
You can host TinyMCE locally or use the cloud version.
It supports custom buttons, icons, and content filtering.
Visit TinyMCE React Docs for advanced configuration options.
Application Insights doesn’t store the original .NET LogLevel
(like Debug
or Trace
) — it only stores SeverityLevel
, which combines them. To make your logs easier to filter and analyze, you can add LogLevel
as a custom property using a TelemetryInitializer
.
Example:
Register the initializer in your app:
services.AddSingleton<ITelemetryInitializer, LogLevelInitializer>();
Now, every trace will include a LogLevel
key in customDimensions
.
It’s best practice to tailor logging levels per environment (Development, Staging, Production) by using environment-specific configuration files like appsettings.Development.json
or appsettings.Production.json
.
Example for Development (verbose logging):
{ "Logging": { "LogLevel": { "Default": "Debug", "Microsoft": "Information", "System": "Warning", "YourAppNamespace": "Trace" } } }
Example for Production (concise logging):
{ "Logging": { "LogLevel": { "Default": "Warning", "Microsoft": "Warning", "System": "Warning", "YourAppNamespace": "Information" } } }
By adjusting log levels per environment, you can capture detailed diagnostics during development while reducing noise and performance impact in production.