How do I create an "internet calendar subscription" for Outlook? - asp.net-mvc-4

Currently, the user adds a "new internet calendar", but it's a one-time download of the ICS file. I want the user to click a button to get his personal calendar added as a subscription to Outlook. I want the automatically updating "internet calendar subscription".
Like in SharePoint, the button called "Connect to Outlook" which adds the calendar you're viewing to your Outlook as an automatically syncing calendar.

Creating iCals in C# and this CodeProject post tell me you should use the DDay iCal Library.
DDay.iCal is an iCal (RFC 5545) class library for .NET 2.0 and above, Silverlight. It aims at being as RFC 5545 compliant as possible, while targeting compatibility with popular calendaring applications, like Apple iCal, Outlook 2007, etc.
Some sample code of iCal + MVC + DDay.iCal
public ActionResult iCalendar(string DownloadFileName)
{
DDay.iCal.iCalendar iCal = new DDay.iCal.iCalendar();
Event evt = iCal.Create<Event>();
evt.Start = iCalDateTime.Today.AddHours(8);
evt.End = evt.Start.AddHours(18); // This also sets the duration
evt.Description = "The event description";
evt.Location = "Event location";
evt.Summary = "18 hour event summary";
evt = iCal.Create<Event>();
evt.Start = iCalDateTime.Today.AddDays(5);
evt.End = evt.Start.AddDays(1);
evt.IsAllDay = true;
evt.Summary = "All-day event";
ISerializationContext ctx = new SerializationContext();
ISerializerFactory factory = new DDay.iCal.Serialization.iCalendar.SerializerFactory();
IStringSerializer serializer = factory.Build(iCal.GetType(), ctx) as IStringSerializer;
string output = serializer.SerializeToString(iCal);
var contentType = "text/calendar";
var bytes = Encoding.UTF8.GetBytes(output);
return File(bytes, contentType, DownloadFileName);
}

Related

Microsoft Graph API - Administrator Consent to update User Calendar

I am working on a App to integrate Microsoft Graph API, is it possible for the administrator of each tenant to give consent for permissions so that the user does not need to have any interaction with our app to give permission so that we can update the user calendar?
Or does the user have to provide authorization at least once in order to get the authorization token?
I have been looking at this guide:
https://learn.microsoft.com/en-gb/graph/auth-v2-service
You can update users' calendar by calling ms graph api without users sign in. But it depends on the api you used if support Application api permission. For example, this api is used to create event for calendar. It support application permission.
I also want to inform you that using application permission is not the best practice because it will give your application such a big permission to manage all users' calendars. But this seems to be your goal.
Let's come back to your requirement. And using the api I mentioned as an example. You firstly need to have an azure ad application and give it the correct api permission and let the tenant admin to consent the permission by clicking "grant admin consent for xx_tenant".
Then you also need to create a client secret for your azure ad application. Going to Azure ad -> Certificates & secrets -> New cient secret. Pls copy the secret. Then assuming you have an asp.net core app used to call the graph api. Then refer to this section or my code below to use graph sdk to call the api. Pls note, graphClient.Users["user_principle"] means who creates the event, the Attendees defines whose calendars will be added events.
using Azure.Identity;
using Microsoft.Graph;
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "your_tenant_name.onmicrosoft.com";
var clientId = "azure_ad_app_id";
var clientSecret = "client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var #event = new Event
{
Subject = "Let's go for lunch",
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = "Does noon work for you?"
},
Start = new DateTimeTimeZone
{
DateTime = "2022-07-15T12:00:00",
TimeZone = "Pacific Standard Time"
},
End = new DateTimeTimeZone
{
DateTime = "2017-07-15T14:00:00",
TimeZone = "Pacific Standard Time"
},
Location = new Location
{
DisplayName = "Harry's Bar"
},
Attendees = new List<Attendee>()
{
new Attendee
{
EmailAddress = new EmailAddress
{
Address = "samanthab#contoso.onmicrosoft.com",
Name = "Samantha Booth"
},
Type = AttendeeType.Required
}
},
AllowNewTimeProposals = true,
TransactionId = "7E163156-7762-4BEB-A1C6-729EA81755A7"
};
await graphClient.Users["user_principle"].Events
.Request()
.Header("Prefer","outlook.timezone=\"Pacific Standard Time\"")
.AddAsync(#event);

Using mailitem.PrintOut() to print a single page?

I'm working on a simple Outlook 2016/2019 VSTO plugin.
When an email is selected and a ribbon button is pressed, it needs to print just the first page of the email to the default printer. mailitem.PrintOut(); works, but will print the whole email. Is there a way to specify the first page only?
var m = e.Control.Context as Inspector;
var mailitem = m.CurrentItem as MailItem;
if (mailitem != null)
{
mailitem.PrintOut();
}
Update: See my answer for the code I used to get this working.
The Outlook object model doesn't provide any property or method for that. You need to parse the message body on your own and use .net mechanisms for printing this piece on your own.
Note, you may try using the Word object model for printing the message bodies (a specific range of pages). The Document.PrintOut method prints all or part of the specified document. Optional parameters allow specifying the page range.
The Outlook object model provides three main ways for working with item bodies:
Body - a string representing the clear-text body of the Outlook item.
HTMLBody - a string representing the HTML body of the specified item.
Word editor - the Microsoft Word Document Object Model of the message being displayed. The WordEditor property of the Inspector class returns an instance of the Document class from the Word object model which you can use to deal with the message body.
You can read more about all these ways in the Chapter 17: Working with Item Bodies.
As #Eugene said, there's no way to specify a single page using mailItem.PrintOut.
I've finally managed to find a way to do this. I save the document as a .doc file in the temp directory, then using Microsoft.Office.Interop.Word to setup the page margins / size and then send the current page to the printer. Hopefully this helps someone as I couldn't find any working examples for c#!
private void btnPrintOnePage_Click(object sender, RibbonControlEventArgs e)
{
string randFile = Path.GetTempPath() + "POP_" + RandomString(35) + ".doc";
var m = e.Control.Context as Inspector;
var mailitem = m.CurrentItem as MailItem;
if (mailitem != null)
{
mailitem.SaveAs(randFile, OlSaveAsType.olDoc);
Word.Application ap = new Word.Application();
Word.Document document = ap.Documents.Open(randFile);
document.PageSetup.PaperSize = Word.WdPaperSize.wdPaperA4;
document.PageSetup.TopMargin = 25;
document.PageSetup.RightMargin = 25;
document.PageSetup.BottomMargin = 25;
document.PageSetup.LeftMargin = 25;
Word.WdPrintOutRange printRange = Word.WdPrintOutRange.wdPrintCurrentPage;
document.PrintOut(false,null,printRange);
document.Close(false, false, false);
File.Delete(randFile);
}
}
public static string RandomString(int length)
{
Random random = new Random();
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}

skype for business automation to outlook

I have to add a feature in Skype for Business to open automatically a new Outlook task window when a call starts, with the phone number of the called/calling contact in the subject field. Is there any addin or api in order to do this?
Thank you
With the help of Lync SDK 2013, new conversation added event can be handled where you can also get participant related information. Inside conversation added event handler listen for AVModality state changes. When AVModality state is changed to connected, using Microsoft.Office.Interop.Outlook outlook application can be automated and new task window can be created as given below
LyncClient lyncClient = new LyncClient();
lyncClient.ConversationManager.ConversationAdded += OnConversationAdded;
private void OnConversationAdded(object sender, Microsoft.Lync.Model.Conversation.ConversationManagerEventArgs e)
{
e.Conversation.Modalities[ModalityTypes.AudioVideo].ModalityStateChanged += OnAudioVideoModalityStateChanged;
}
private void OnAudioVideoModalityStateChanged(object sender, ModalityStateChangedEventArgs e)
{
switch(e.NewState)
{
case ModalityState.Connected:
Application oOutlook = null;
oOutlook = new Application();
TaskItem oTask = (TaskItem)oOutlook.CreateItem(OlItemType.olTaskItem);
oTask.Subject = "Testing";
oTask.StartDate = DateTime.Now;
oTask.Display(true);
break;
}
}
For more information :
Microsoft.Office.Interop.Outlook,
Lync SDK 2013

How do I add a custom mail header using the Office365 Preview API

I can't find anything in the preview API or the Microsoft.Office365.Exchange namespace to let me create a custom header or get the existing headers. Here's my code create the email and the recipients.
//Create the new Message with the Office365 API and save it to the Drafts folder
var client = await EnsureClientCreated();
var o365Message = new Microsoft.Office365.Exchange.Message();
string subject = "Test subject";
o365Message.Subject = subject;
o365Message.Body = new ItemBody() { Content = "Test", ContentType = BodyType.Text };
messageModel.Subject = subject;
var recip = new Recipient();
recip.Address = "test#test.com";
o365Message.ToRecipients.Add(recip);
await client.Me.Drafts.Messages.AddMessageAsync(o365Message, false);
Thx,
This isn't available right now from the service. I see nothing about mail headers in the metadata document. Please use UserVoice to request this feature.

Problem with generating XPS documents with images in a WCF class library

I have a Silverlight application which uses a web service in order to create XPS documents. The document templates are created as XAML controls in a WCF class library.
public void GenerateXPS()
{
Type typeofControl = Type.GetType(DOCUMENT_GENERATOR_NAMESPACE + "." + ControlTypeName, true);
FrameworkElement control = (FrameworkElement)(Activator.CreateInstance(typeofControl));
control.DataContext = DataContext;
FixedDocument fixedDoc = new FixedDocument();
PageContent pageContent = new PageContent();
FixedPage fixedPage = new FixedPage();
//Create first page of document
fixedPage.Children.Add(control);
((IAddChild)pageContent).AddChild(fixedPage);
fixedDoc.Pages.Add(pageContent);
XpsDocument xpsd = new XpsDocument(OutputFilePath + "\\" + OutputFileName, FileAccess.ReadWrite);
System.Windows.Xps.XpsDocumentWriter xw = XpsDocument.CreateXpsDocumentWriter(xpsd);
xw.Write(fixedDoc);
xpsd.Close();
SaveToDocumentRepository();
}
In order to bind the actual data to my document template I set the DataContext property of the control. The problem is that when I look at my XPS, the images (I bind the Source of my Image controls to a string property that represents the URL of my image) are not displayed as if they were not loaded. How can I solve this problem? Thanks!
The binding infrastructure probably needs a push along because you are operating outside the intended use of WPF.
Try adding the following code after setting the datacontext:
control.DataContext = DataContext;
// we need to give the binding infrastructure a push as we
// are operating outside of the intended use of WPF
var dispatcher = Dispatcher.CurrentDispatcher;
dispatcher.Invoke(
DispatcherPriority.SystemIdle,
new DispatcherOperationCallback(delegate { return null; }),
null);
I cover this and other XPS related stuff in this blog post.