How to add an Extension to Outlook 365 event using Microsoft.Graph? - c#

I'm using Microsoft.Graph to create an Office365 calendar event. It works fine and I can create an event but I need to add a couple of extra string properties to an event, so I've created an extension for that. It compiles fine. But when I try to run it and create an event with added extension, it throws an error:
Code: RequestBodyRead
Message: The property 'extensionName' does not exist on type 'Microsoft.OutlookServices.Extension'. Make sure to only use property names that are defined by the type or mark the type as open type.
//Extension
var evExtCollPage = new EventExtensionsCollectionPage();
var dict = new Dictionary<string,object>();
dict.Add("eSmtTickeId", "123");
dict.Add("siteId", "456");
var openExtension = new OpenTypeExtension
{
ExtensionName = "com.TechApp.Extensions",
AdditionalData = dict
};
evExtCollPage.Add(openExtension);
Event createdEvent = await graphClient.Me.Events.Request().AddAsync(new Event
{
Subject = "Service appointment",
Location = location,
Attendees = attendees,
Body = body,
Start = startTime,
End = endTime,
Extensions = evExtCollPage
});
What is wrong with my extension? I've struggled with this for 3 days now.

Adding the ODataType has worked for me:
var openExtension = new OpenTypeExtension
{
ODataType = "microsoft.graph.openTypeExtension",
ExtensionName = "com.TechApp.Extensions",
AdditionalData = dict
};

Related

C# AWS CDK Serverless, publish new version Lambda and create new API resource

I'm new to AWS CDK and what I'm trying to accomplish (using C#) is to version my lambda function, and then create a new API resource referencing the version.
For example: The program accepts a version parameter.
internal CdkAppStack(Construct scope, string id, IStackProps props, string bucketName, string functionName, string version) : base(scope, id, props)
{
var bucket = new Bucket(this, bucketName, new BucketProps {
BucketName = bucketName
});
var handler = new Function(this, $"{functionName}Handler", new FunctionProps
{
Runtime = Runtime.DOTNET_CORE_3_1,
Code = Code.FromAsset("Lambdas\\src\\Lambdas\\bin\\Debug\\netcoreapp3.1"),
Handler = "Lambdas::Lambdas.Function::FunctionHandler",
Environment = new Dictionary<string, string>
{
["BUCKET"] = bucket.BucketName,
},
FunctionName = functionName
});
string apiName = !string.IsNullOrEmpty(version) ? $"{functionName}-{version}" : functionName;
bucket.GrantReadWrite(handler);
var api = new RestApi(this, $"{apiName}-API", new RestApiProps
{
RestApiName = $"{apiName}API",
Description = $"This service the Lambda - {functionName}.",
RetainDeployments = true
});
var getWidgetsIntegration = new LambdaIntegration(handler, new LambdaIntegrationOptions
{
RequestTemplates = new Dictionary<string, string>
{
["application/json"] = "{ \"statusCode\": \"200\" }"
}
});
string resource = !string.IsNullOrEmpty(version) ? $"execute-{version}" : "execute";
var helloWorldResource = api.Root.AddResource(resource);
var method = helloWorldResource.AddMethod("POST", getWidgetsIntegration);
}
Actual result:
It overrides the lambda and api resource.
Expected result:(version parameter is 3). Added new resource (execute-3)
AWS Console - Expected result
For the given code the process probably looks like this:
Current provisioned state includes execute-2
CDK synthesizes a Cloudformation template where execute-3 exists and execute-2 does not exist.
Cloudformation figures out that in order to reach the desired state (described in the template) it needs to delete execute-2 and provision execute-3.
If you literally want to reach what you are describing you will have to add resources and not delete previously provisioned ones (say write a loop that runs over 1..version and adds all past versions)
Another (less recommendable) option is to use a deletion policy. This way you can hint cloudformation not the delete execute-2 (the downside here is that execute-2's lifecycle is no longer managed by any stack --> you will have to manage changes to it manually)

DNN attach file to Notification

I am using DNN 9 and I want to send a notification with an attachment file, but seems that DNN doesn't allow to do that.
Is there is a way (or any workaround) to do that?
Here is the DNN code of the NotificationsController
and here is my code that calls the DNN code
//...
Notification dnnNotification = new Notification
{
NotificationTypeID = notification.NotificationTypeId,
From = notification.From,
Subject = notification.Subject,
Body = notification.Body
};
NotificationsController.Instance.SendNotification(dnnNotification, portalId, dnnRoles, dnnUsers);
You cannot attach a file to a notification in DNN. BUT, you can add custom notification actions to a notification type. These actions result in links added under the notification (like the default "Dismiss" action to mark the notification as "read").
In order to send a notification, you need to create a NotificationType to associate that to. The NotificationTypeAction are added to the type. So whenever you send a notification of a certain type, the actions go with it.
You could create a NotificationTypeAction and name it "Download Attachment". When a user clicks the link, it will call a custom api service. That service could serve up the file.
Here is some sample code in which I create a custom type with 1 custom action:
public void AddNotificationType()
{
var actions = new List<NotificationTypeAction>();
var deskModuleId = DesktopModuleController.GetDesktopModuleByFriendlyName(Constants.DESKTOPMODULE_FRIENDLYNAME).DesktopModuleID;
var objNotificationType = new NotificationType
{
Name = Constants.NOTIFICATION_FILEDOWNLOAD,
Description = "Get File Attachment",
DesktopModuleId = deskModuleId
};
if (NotificationsController.Instance.GetNotificationType(objNotificationType.Name) == null)
{
var objAction = new NotificationTypeAction
{
NameResourceKey = "DownloadAttachment",
DescriptionResourceKey = "DownloadAttachment_Desc",
APICall = "DesktopModules/MyCustomModule/API/mynotification/downloadfile",
Order = 1
};
actions.Add(objAction);
NotificationsController.Instance.CreateNotificationType(objNotificationType);
NotificationsController.Instance.SetNotificationTypeActions(actions, objNotificationType.NotificationTypeId);
}
}
Then use code like the following to send the notification:
public void SendNotification(UserInfo userToReceive)
{
// Get the notification type; if it doesn't exist, create it
ModuleController mCtrl = new ModuleController();
var itemAddedNType = NotificationsController.Instance.GetNotificationType(Constants.NOTIFICATION_FILEDOWNLOAD);
if (itemAddedNType == null)
{
AddNotificationType();
itemAddedNType = NotificationsController.Instance.GetNotificationType(Constants.NOTIFICATION_FILEDOWNLOAD);
}
if (itemAddedNType != null)
{
Notification msg = new Notification
{
NotificationTypeID = itemAddedNType.NotificationTypeId,
Subject = "A file is ready to download.",
Body = alertBody,
ExpirationDate = DateTime.MaxValue,
IncludeDismissAction = true,
};
List<UserInfo> sendUsers = new List<UserInfo>();
sendUsers.Add(userToReceive);
NotificationsController.Instance.SendNotification(msg, itemModule.PortalID, null, sendUsers);
}
}
For a full tutorial on DNN Notifications, I highly recommend subscribing to DNNHero.com and watching this 3-part series which comes with sample code.
https://www.dnnhero.com/Premium/Tutorial/ArticleID/265/DNN-Notifications-Introduction-Part-1-3

How to create New EPT by using CSOM

I try to create a new EPT (project server 2013) using C# CSOM library.
But It has following error occurred.
"PJClientCallableException: EnterpriseProjectTypeInvalidCreatePDPUid"
Couple of article tell to change the "IsCreate=true". But it does not success for me. Here is the code what I have done.
public void CreateEnterpriseProjectType(Guid eptGuid, string eptName, string eptDescription)
{
ProjectContext pwaContext = new ProjectContext(this.PWA_URL);
EnterpriseProjectTypeCreationInformation eptData = new EnterpriseProjectTypeCreationInformation();
eptData.Id = eptGuid;
eptData.Name = eptName;
eptData.Description = eptDescription;
eptData.IsDefault = false;
eptData.IsManaged = true;
eptData.WorkspaceTemplateName = "PROJECTSITE#0";
eptData.ProjectPlanTemplateId = Guid.Empty;
eptData.WorkflowAssociationId = Guid.Empty;
eptData.Order = 4;
List<ProjectDetailPageCreationInformation> projectDetailPages = new
List<ProjectDetailPageCreationInformation>() {
new ProjectDetailPageCreationInformation() {
Id = pwaContext.ProjectDetailPages[1].Id, IsCreate = true }
};
eptData.ProjectDetailPages = projectDetailPages;
pwaContext.Load(pwaContext.EnterpriseProjectTypes);
pwaContext.ExecuteQuery();
EnterpriseProjectType newEpt = pwaContext.EnterpriseProjectTypes.Add(eptData);
pwaContext.EnterpriseProjectTypes.Update();
pwaContext.ExecuteQuery();
}
Can anyone explain the issue or provide the working code part.
I would like to suggest the following:
Define an enterprise project type:
string basicEpt = "Enterprise Project"; // Basic enterprise project type.
int timeoutSeconds = 10; // The maximum wait time for a queue job, in seconds.
And then, when you create the new project, work like this:
ProjectCreationInformation newProj = new ProjectCreationInformation();
newProj.Id = Guid.NewGuid();
newProj.Name = "Project Name";
newProj.Description = "Test creating a project with CSOM";
newProj.Start = DateTime.Today.Date;
// Setting the EPT GUID is optional. If no EPT is specified, Project Server
// uses the default EPT.
newProj.EnterpriseProjectTypeId = GetEptUid(basicEpt);
PublishedProject newPublishedProj = projContext.Projects.Add(newProj);
QueueJob qJob = projContext.Projects.Update();
// Calling Load and ExecuteQuery for the queue job is optional.
// projContext.Load(qJob);
// projContext.ExecuteQuery();
JobState jobState = projContext.WaitForQueue(qJob, timeoutSeconds);
When the last line of that piece of code ends, the project must be created and published in order to define tasks or whatever.
I don't know what is happening to your code, seems great.
Hope it helps to you,

Dynamics CRM how to get list of all entities

Working with CRM 2013, how can I get a list of all entities in the CRM via the connectionManager class? I want to get all the entities for the current connection.
Thank you for your comment and answer it work now,
this is my function
public static EntityMetadata[] GetEntities ( IOrganizationService organizationService)
{
Dictionary<string, string> attributesData = new Dictionary<string, string>();
RetrieveAllEntitiesRequest metaDataRequest = new RetrieveAllEntitiesRequest();
RetrieveAllEntitiesResponse metaDataResponse = new RetrieveAllEntitiesResponse();
metaDataRequest.EntityFilters = EntityFilters.Entity;
// Execute the request.
metaDataResponse = (RetrieveAllEntitiesResponse)organizationService.Execute(metaDataRequest);
var entities = metaDataResponse.EntityMetadata;
return entities;
}
and i call my function in the windows app form like this:
var allEntities = CRMHelpers.GetEntities(service);
foreach (EntityMetadata Entity in allEntities)
{
cbxEntity.Items.Add(Entity.LogicalName);
}
If you are looking for getting the entity metadata using code (C#) then we have inbuilt messages to get all entities and if required attribute level information as well. You can use the message "RetrieveAllEntitiesRequest". A sample code would be as follows to achieve the same.
RetrieveAllEntitiesRequest retrieveAllEntityRequest = new RetrieveAllEntitiesRequest
{
RetrieveAsIfPublished = true,
EntityFilters = EntityFilters.Attributes
};
RetrieveAllEntitiesResponse retrieveAllEntityResponse = (RetrieveAllEntitiesResponse)serviceProxy.Execute(retrieveAllEntityRequest);
If you need to get a specific entity information then you may use the message "RetrieveEntityRequest". A sample for the same would be as follows,
RetrieveEntityRequest entityRequest = new RetrieveEntityRequest
{
EntityFilters = EntityFilters.Attributes,
LogicalName = entityName,
RetrieveAsIfPublished = true
};
RetrieveEntityResponse entityResponse = (RetrieveEntityResponse)serviceProxy.Execute(entityRequest);
Hope this is what you were looking for. Let us know if you need any more information on the same.

RemoveExtendedProperty throws error when used on an occurrence of a recurring appointment

I am developing an application that syncs an exchange calendar to another calendar. I put extended properties on the exchange appointments in order to preserve the mapping between appointments in the two calendars. Everything is working fine until I try to remove an extended property from an occurrence of a recurring appointment. When I try doing this, I get the error:
The delete action is not supported for this property.
Here is a code snippet that demonstrates the error:
public void ExchangeTest()
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1)
{
Credentials = new NetworkCredential("username", "password", "domain")
};
service.AutodiscoverUrl("username#domain.com");
Appointment appt = new Appointment(service)
{
Recurrence = new Recurrence.DailyPattern(DateTime.Now, 2) { NumberOfOccurrences = 3},
Start = DateTime.Now,
End = DateTime.Now.AddHours(2),
Subject = "Test Appointment"
};
NameResolutionCollection resolutionCollection = service.ResolveName("username", ResolveNameSearchLocation.DirectoryOnly, false);
string mailboxAddress = resolutionCollection.First().Mailbox.Address;
FolderId folderId = new FolderId(WellKnownFolderName.Calendar, mailboxAddress);
appt.Save(folderId);
PropertySet properties = new PropertySet(AppointmentSchema.ICalUid);
appt.Load(properties);
CalendarView view = new CalendarView(DateTime.Today, DateTime.Today.AddDays(8)){PropertySet = properties};
IEnumerable<Appointment> occurrences = service.FindAppointments(folderId, view)
.Where(a => a.ICalUid == appt.ICalUid);
ExtendedPropertyDefinition definition = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.PublicStrings, "TestProperty", MapiPropertyType.String);
Appointment firstOccurrence = occurrences.First();
firstOccurrence.SetExtendedProperty(definition, "test");
firstOccurrence.Update(ConflictResolutionMode.AutoResolve);
//The error occurs on the next line.
firstOccurrence.RemoveExtendedProperty(definition);
firstOccurrence.Update(ConflictResolutionMode.AutoResolve);
//clean up
appt.Delete(DeleteMode.HardDelete);
}
It appears that the error is only thrown for an Exchange 2007 server (It works on 2010). Am I doing something wrong, or is this a problem with Exchange? Is there a way to work around this issue? Any help will be appreciated.
I ended up not using the RemoveExtendedProperty function. Instead, I worked around it by just setting the property again, but setting it to an empty space. I then handled the empty space in code. This appears to be a problem with Exchange or the managed API.
Did you try;
appointment.Delete(DeleteMode.SoftDelete,SendCancellationsMode.SendToAllAndSaveCopy);

Categories