Query sharepoint list from MVC site - asp.net-mvc

Ok i have a fairly simple request, but i have been searching for some hours now and can't seem to find a simple answer to what i feel should be a fairly simple task.
I have built an intranet site for our business using dot net & MVC this runs on a separate server to the sharepoint site. All i want to do is get a list of documents from a given sharepoint library and display links to their urls which will redirect the end user to that document from my intranet site - this will vary depending on the users dept.
So i was looking at the jquery AJAX route, but then i realise sharepoint wont allow me javascript queries from a different domain.
So next route is backend dot net pass the data to the view and display that way, but i want to use the servers sharepoint authentication without entering username and password in the code/manually.
Am i missing something simple? I don't want to waste a lot of time on something i thought should be fairly simple.. anyone fancy pointing me in the right direction?
Thanks

Well it wasn't incredibly easy but i did get it done like this if anyone wants to know :p sp 2013 using Rest api using server credentials to connect to sharepoint and retrieve documents Name, Sharepoint url and icon.
Imports System.Xml
Imports System.IO
Imports System.DirectoryServices.AccountManagement
Imports System.Linq
Imports System.Net
Public Class SPDocumentLibrary
Public Property Files As List(Of SPDocument)
Public Sub New()
Dim request As HttpWebRequest = DirectCast(WebRequest.Create(
"http://sharepointserver/_api/web/lists/getByTitle('list')/items?$expand=File&$select=File/Name,OData__dlc_DocIdUrl/Url&$orderby=Title&$top=99999&orderby=File/Name"
), HttpWebRequest)
request.Method = "GET"
request.ContentType = "text/xml"
request.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials
Dim response As HttpWebResponse = CType(request.GetResponse(), HttpWebResponse)
Dim receiveStream As Stream = response.GetResponseStream()
Dim readStream As New StreamReader(receiveStream, Encoding.UTF8)
Dim xd As XDocument = XDocument.Load(readStream)
response.Close()
readStream.Close()
Dim d As XNamespace = "http://schemas.microsoft.com/ado/2007/08/dataservices"
Dim x As XNamespace = "http://www.w3.org/2005/Atom"
Dim docs As IEnumerable(Of SPDocument) = _
From doc As XElement In xd.Root.Elements(x + "entry") _
Select New SPDocument With {.Name = Path.GetFileNameWithoutExtension(doc.Descendants(d + "Name").Value), .Url = doc.Descendants(d + "Url").Value, .icon = IconFromExtension(Path.GetExtension(doc.Descendants(d + "Name").Value).ToLower)}
Me.Files = docs.ToList()
End Sub
Private Function IconFromExtension(ext As String) As String
If ext Like ".doc*" Then
Return "icdoc.png"
ElseIf ext Like ".xls*" Then
Return "icxls.png"
ElseIf ext Like ".ppt*" Then
Return "icppt.png"
ElseIf ext = ".pdf" Then
Return "icpdf.png"
ElseIf ext = ".msg" Then
Return "icmsg.png"
ElseIf ext Like ".htm*" Then
Return "ichtm.gif"
ElseIf ext Like ".rtf" Then
Return "icrtf.gif"
ElseIf ext Like ".dot*" Then
Return "icdot.png"
ElseIf ext Like ".xlt*" Then
Return "icxlt.png"
Else
Return "icgen.gif"
End If
End Function
End Class
Public Class SPDocument
Property Name As String
Property Url As String
Property icon As String
End Class

Related

Retrieve file attachment from MMS via ASP.NET MVC controller

I'm trying out the Twilio service to interact with individuals via SMS/MMS. I've sorta figured out how to send MMS messages to initiate the "conversation" and that seems to be working well. However, now I'm trying to build a system to respond to the incoming messages on my SMS/MMS-enabled test number. I'm working from one of the examples I found on the Twilio documentation site to build an ASP.NET MVC web service to handle the conversation (VB.NET):
Imports System.Web.Mvc
Imports Twilio.AspNet.Common
Imports Twilio.AspNet.Mvc
Imports Twilio.TwiML
Namespace Controllers
Public Class SMSController
Inherits TwilioController
' GET: SMS
Function Index(ByVal IncomingSMS As SmsRequest) As TwiMLResult
Dim SMSResponse As New MessagingResponse
Dim SMSMessage As String = IncomingSMS.Body
Dim JediCode As String = "There is no emotion, there is peace."
Dim SithCode As String = "Peace is a lie. There is only Passion."
JediCode += vbCrLf & "There is no ignorance, there is knowledge."
JediCode += vbCrLf & "There is no passion, there is serenity."
JediCode += vbCrLf & "There is no chaos, there is harmony."
JediCode += vbCrLf & "There is no death, there is the Force."
SithCode += vbCrLf & "Through Passion, I gain Strength."
SithCode += vbCrLf & "Through Strength, I gain Power."
SithCode += vbCrLf & "Through Power, I gain Victory."
SithCode += vbCrLf & "Through Victory my chains are Broken."
SithCode += vbCrLf & "The Force shall free me."
If SMSMessage IsNot Nothing Then
If SMSMessage.ToUpper.Trim = "JEDI" Then
SMSResponse.Message(JediCode)
ElseIf SMSMessage.ToUpper.Trim = "SITH" Then
SMSResponse.Message(SithCode)
Else
SMSResponse.Message("Ahsoka? Is that you?")
End If
Else
SMSResponse.Message("What did you want to know?")
End If
Return TwiML(SMSResponse)
End Function
End Class
End Namespace
Yes, this is all just "play" stuff that I'm using for testing and will eventually be replaced with something more appropriate to the purpose, but I want to try and figure it all out before I get too deep into the reality of things.
I've set up the site on my IIS server, registered the DNS, and even gotten my SSL certificate set up. Everything seems to be working great with my simple testing so far, but there are a couple of things that I still haven't been able to figure out so far and I'm hoping someone here can point me in the right direction.
I'll ask each as a separate question, but here's the first: how do I retrieve the attachment from an MMS message?
I'd like to be able to receive PDFs (and possibly other file types) and pass them along via email to an appropriate individual or department. I know how to do the emailing, but I haven't been able to find appropriate documentation for how to retrieve the attachment(s) in the MMS message to actually include it in that email process.
When I try to access the properties of the IncomingSMS (SmsRequest) object, I don't find any reference to Media in any of them - no NumMedia, no MediaUri, nothing. There doesn't appear to be an MmsRequest object type (that I've found yet, anyway).
What am I overlooking here to be able to retrieve the PDF I sent to my test number for further processing? Should I change the method's definition to accept the object as a MessageResource or something?
EDIT: I forgot to mention that I checked the Twilio console and see that the message was apparently received successfully with the attachment, so I know that at least that part is working properly.
I've asked a second, related question that goes along with this one to help "finalize" some things for our goals.
The SmsRequest class that you're using comes from the Twilio helper library for ASP.NET which aims to make it easier to integrate Twilio into ASP.NET. However, the SmsRequest and other classes do not cover all possible webhook parameters. If there's parameters missing from the class, you can still retrieve the parameters manually instead of relying on MVC Model Binding.
Based on this C# sample, I created a VB.NET sample to show how to receive and save incoming MMS files:
Imports System.IO
Imports System.Net.Http
Imports System.Threading.Tasks
Imports MimeTypes
Imports Twilio.AspNet.Mvc
Imports Twilio.TwiML
Imports Twilio.TwiML.Messaging
Public Class HomeController
Inherits TwilioController
Shared httpClient As HttpClient = New HttpClient
Async Function Index() As Task(Of TwiMLResult)
Dim response As New MessagingResponse
Dim message As New Message
Dim numMedia = Short.Parse(If(Request.Form.Get("NumMedia"), 0))
If numMedia = 0 Then
response.Message("No file received.")
Return TwiML(response)
End If
For mediaIndex As Integer = 0 To numMedia - 1
Dim mediaUrl = Request.Form.Get($"MediaUrl{mediaIndex}")
Dim contentType = Request.Form.Get($"MediaContentType{mediaIndex}")
Dim saveFilePath = Server.MapPath(String.Format(
"~/App_Data/{0}{1}",
Path.GetFileName(mediaUrl),
MimeTypeMap.GetExtension(ContentType)
))
Await DownloadUrlToFileAsync(mediaUrl, saveFilePath)
Next
response.Message("File received.")
Return TwiML(response)
End Function
Private Async Function DownloadUrlToFileAsync(mediaUrl As String, saveFilePath As String) As Task
Dim Response = Await httpClient.GetAsync(mediaUrl)
Dim httpStream = Await Response.Content.ReadAsStreamAsync()
Using fileStream As Stream = IO.File.Create(saveFilePath)
Await httpStream.CopyToAsync(fileStream)
Await fileStream.FlushAsync()
End Using
End Function
End Class
You can probably simplify the code a little by assuming there's only one file going to be sent over MMS, but it's a good idea to handle other cases too.
To get the correct file extension, I'm using this
MimeTypeMap library, but you can roll your own solution.
By default the files from the incoming MMS are publicly available via the MediaUrl{mediaIndex} URL, but it's a good idea to turn on Basic Auth for these media files.
If you're turning on Basic Auth for media files, you'll need to add the authentication header to the HTTP requests, like this:
Imports System.IO
Imports System.Net.Http
Imports System.Net.Http.Headers
Imports System.Threading.Tasks
Imports MimeTypes
Imports Twilio.AspNet.Mvc
Imports Twilio.TwiML
Imports Twilio.TwiML.Messaging
Public Class HomeController
Inherits TwilioController
Shared httpClient As HttpClient = CreateHttpClient()
Private Shared Function CreateHttpClient() As HttpClient
Dim client As New HttpClient
Dim appSettings As NameValueCollection = ConfigurationManager.AppSettings
If Boolean.Parse(If(appSettings.Get("TwilioUseBasicAuthForMedia"), False)) Then
Dim authString = $"{appSettings.Get("TwilioAccountSid")}:{appSettings.Get("TwilioAuthToken")}"
authString = Convert.ToBase64String(Encoding.ASCII.GetBytes(authString))
client.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Basic", authString)
End If
Return client
End Function
...
End Class
I'm retrieving the TwilioUseBasicAuthForMedia, TwilioAccountSid, and TwilioAuthToken from the Web.config appSettings.
(Make sure you don't check those secrets into source control, and use UserSecretsConfigBuilder instead, to securely set the secrets).
Here's the source code on GitHub.
You're welcome to submit a GitHub issue and/or a PR to add support for these missing parameters to the SmsRequest. Tho, it wouldn't be as easy as normal model binding because the number of parameters increases as more files are sent over MMS.

Configure Teams call forwarding policy via MS Graph API

TL;DR:
what's the MS Graph API for setting the teams call forwarding policy of an user?
Background:
Currently I'm trying to migrate a Lync/Skype-based .NET application to Teams.
The Teams related part is about setting the call forwarding preferences of a few specific users.
Those users have direct routing enabled, i.e. you can call a fixed PSTN/suffix number and the user will receive the call on his mobile. That mobile number is depending on the shift, so the programm is adapting it to whoever has the shift duty at that time.
What I've tried so far?
I can authenticate with the MS Graph API.
I know that there's TAC extension for this purpose ([1] and [2])
There's also a Powershell extension [3]
I'm not the first one to ask the question, but other threads usually got stuck [4]
The Call-Redirect is not what I want, as I'm not actively listening on those instances.
There's a github for Teams related scripts, but unfortunately without sources ...
I haven't yet reflected the Powershell extension
There is a promising user settings entry, where you can change shifts but not the call forwarding
Plan B?
invoke the powershell cmdlet, but that seems to be so 2000-ish
Update 2022-06-20
I'm starting to reflect the ps module. So API seems to be something like https://api.interfaces.records.teams.microsoft.com/Skype.VoiceGroup/userRoutingSettings/ + userId
The teams user id can be retrieved
Some parts of teams rely still on an older REST API (german only, sorry)
Update 2022-06-30
a POC which can be improved would look like this (... if I've packed into the usual AcquireTokenOnBehalfOf, then I'll add it as an answer ...)
Imports System.IO
Imports Microsoft.Identity.Client
Imports System.Globalization
Imports System.Net.Http
Imports System.Text
Imports System.Net.Http.Headers
Imports System.Net
Imports Newtonsoft.Json
Imports System.IdentityModel.Tokens.Jwt
Public Class LyncTest
Public Shared Sub Test()
Dim InstanceId As String = "https://login.microsoftonline.com/"
Dim RedirectURI As String = "https://login.microsoftonline.com/common/oauth2/nativeclient"
' Ids / Secrets and can be found on your Azure application page
Dim TenantId As String = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Dim AppId As String = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Dim secretVal As String = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Dim username As String = "xxxxxxx.xxxxxx#xxxxxxxxxxxx.com"
Dim password As String = "xxxxxxxxxxxx"
' Teams scope
Dim scope As String = "48ac35b8-9aa8-4d74-927d-1f4a14a0b239/.default"
Dim httpClient = New HttpClient()
' start resource owner password credential flow
' see https://learn.microsoft.com/en-us/powershell/module/teams/connect-microsoftteams?view=teams-ps#example-4-connect-to-microsoftteams-using-accesstokens
Dim baseParam As String =
$"client_id={AppId}" &
$"&username={WebUtility.UrlEncode(username)}" &
$"&password={WebUtility.UrlEncode(password)}" &
$"&grant_type=password" &
$"&client_secret={WebUtility.UrlEncode(secretVal)}" &
$"&scope={scope}"
' get user_impersonation token
Dim tokenReq As New HttpRequestMessage(HttpMethod.Post, $"https://login.microsoftonline.com/{TenantId}/oauth2/v2.0/token") With {
.Content = New StringContent(baseParam, Encoding.UTF8, "application/x-www-form-urlencoded")
}
Dim TokenRes As HttpResponseMessage = httpClient.SendAsync(tokenReq).Result
Dim TokenObj As GraphToken = JsonConvert.DeserializeObject(Of GraphToken)(TokenRes.Content.ReadAsStringAsync.Result())
Dim JwtReader As New JwtSecurityTokenHandler
Dim JwtToken As JwtSecurityToken = JwtReader.ReadToken(TokenObj.AccessToken)
Dim UserOid As String = JwtToken.Payload("oid")
' set user calling routing
Dim RoutingURL As String = $"https://api.interfaces.records.teams.microsoft.com/Skype.VoiceGroup/userRoutingSettings/{UserOid}"
httpClient.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", TokenObj.AccessToken)
Dim RoutingJSON As String =
"{""sipUri"":""sip:andreas.beeker#kraiburg-tpe.com""," &
"""forwardingSettings"":{""isEnabled"":false,""forwardingType"":""Simultaneous"",""targetType"":""Unknown"",""target"":""""}," &
"""unansweredSettings"":{""isEnabled"":true,""targetType"":""SingleTarget"",""target"":""+491701234567"",""delay"":""00:00:20""}," &
"""callGroupDetails"":{""targets"":[],""order"":""Simultaneous""},""callGroupMembershipSettings"":{""callGroupMembershipDetails"":[]}}"
Dim RoutingReq As New HttpRequestMessage(HttpMethod.Post, RoutingURL) With {
.Content = New StringContent(RoutingJSON, Encoding.UTF8, "application/json")
}
Dim RoutingRes As HttpResponseMessage = httpClient.SendAsync(RoutingReq).Result
Console.WriteLine(If(RoutingRes.IsSuccessStatusCode, "success", "failed"))
End Sub
Public Class GraphToken
<JsonProperty(PropertyName:="access_token")>
Public Property AccessToken As String
<JsonProperty(PropertyName:="expires_in")>
Public Property ExpiresIn As Integer
<JsonProperty(PropertyName:="ext_expires_in")>
Public Property ExpiresInExt As Integer
<JsonProperty(PropertyName:="scope")>
Public Property Scope As String
<JsonProperty(PropertyName:="token_type")>
Public Property TokenType As String
End Class
End Class
There is no Graph API available for setting the teams call forwarding policy of an user.
Any user policy/tenant configuration are only exposed through PowerShell or admin portal now.
If you just want to change the forwarding status in Teams without catching callId and transferring individual calls, there is a simpler way by using PowerShell:
Install PowerShell module for M$Teams
https://www.powershellgallery.com/packages/MicrosoftTeams straight to PowerShell, for example by using
Install-Module -Name MicrosoftTeams -RequiredVersion 4.6.0 -AllowClobber
Assuming that you have permission set up forwarding by using Set-CsUserCallingSettings command, for example
Set-CsUserCallingSettings -Identity user#email.com -IsUnansweredEnabled $FALSE
Set-CsUserCallingSettings -Identity user#email.com -IsForwardingEnabled $true -ForwardingType Immediate -ForwardingTargetType SingleTarget -ForwardingTarget "+123456789"
In theory, only the second line is necessary, but I've noticed that PowerShell throws an error if Voicemail is enabled
This will change the forwarding status for all calls incoming to the selected identity. Note, that the user can change it still in Teams GUI.

Save file to path desktop for current user

I have a project ASP.NET Core 2.0 MVC running on IIS.
Want to Export some information from data grid to Excel and save it from web page to the desktop of current user.
string fileName = "SN-export-" + DateTime.Now + ".xlsx";
Regex rgx = new Regex("[^a-zA-Z0-9 -]");
fileName = rgx.Replace(fileName, ".");
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string fileName2 = Path.Combine(path, fileName);
FileInfo excelFile = new FileInfo(fileName2);
excel.SaveAs(excelFile);
This works perfect local at Visual Studio, but not after publishing at IIS.
Using simple path string path = #"C:\WINDOWS\TEMP"; It will save this export file at the server temp folder, but not current web page user.
How to get this?
ASP.NET MVC is framework for a web application. So you have fronted and backend parts. This code will executed on the server side of your application. Even if you use Razor pages, they also generated at the backend. So there are several ways to save data on the computer:
use js to iterate data and save it, but I'm not sure that saving to excel with js is easy;
send desired data to backend, save it to excel and then return to the client.
For a second way you can use next code:
[Route("api/[controller]")]
public class DownloadController : Controller {
//GET api/download/12345abc
[HttpGet("{id}"]
public async Task<IActionResult> Download(YourData data) {
Stream stream = await {{__get_stream_based_on_your_data__}}
if(stream == null)
return NotFound();
return File(stream, "application/octet-stream"); // returns a FileStreamResult
}
}
And because of security reasons you can save data only to downloads directory.

Not enough storage is available for `Console.ReadLine`.`

I am using a dual service/console model to test a service of mine. The code in the spotlight is:
static void Main(string[] args)
{
// Seems important to use the same service instance, regardless of debug or runtime.
var service = new HostService();
service.EventLog.EntryWritten += EventLogEntryWritten;
if (Environment.UserInteractive)
{
service.OnStart(args);
Console.WriteLine("Host Service is running. Press any key to terminate.");
Console.ReadLine();
service.OnStop();
}
else
{
var servicesToRun = new ServiceBase[] { service };
Run(servicesToRun);
}
}
When I run the app under the debugger, using F5, on the line Console.ReadLine(); I get a System.IO.IOException, with "Not enough storage is available to process this command."
The only purpose of the ReadLine is to wait until someone presses a key to end the app, so I can't imagine where the data is coming from that needs so much storage.
This is a service, and its output is likely set to Windows Application, change the output to Console Application and this should go away.
I having the same problem, I found the setting under project properties but I am creating a windows application so I can not change the application type.
This is the code I use.
Dim t As Task = New Task(AddressOf DownloadPageAsync)
t.Start()
Console.WriteLine("Downloading page...")
Console.ReadLine()
Async Sub DownloadPageAsync()
Using client As HttpClient = New HttpClient()
Using response As HttpResponseMessage = Await client.GetAsync(page)
Using content As HttpContent = response.Content
' Get contents of page as a String.
Dim result As String = Await content.ReadAsStringAsync()
' If data exists, print a substring.
If result IsNot Nothing And result.Length > 50 Then
Console.WriteLine(result.Substring(0, 50) + "...")
End If
End Using
End Using
End Using
End Sub

Why doesn't my PDF document render/download in ASP.NET MVC2?

I have an ASP.NET MVC2 application in development and I am having problems rendering a .pdf file from our production server.
On my Visual Studio 2010 integrated development server everything works fine, but after I publish the application to the production server, it breaks. It does not throw any exceptions or errors of any kind, it simply does not show the file.
Here's my function for displaying the PDF document:
public static void PrintExt(byte[] FileToShow, String TempFileName,
String Extension)
{
String ReportPath = Path.GetTempFileName() + '.' + Extension;
BinaryWriter bwriter =
new BinaryWriter(System.IO.File.Open(ReportPath, FileMode.Create));
bwriter.Write(FileToShow);
bwriter.Close();
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = ReportPath;
p.StartInfo.UseShellExecute = true;
p.Start();
}
My production server is running Windows Server 2008 and IIS 7.
You cannot expect opening the default program associated with PDF file browsing on the server. Try returning the file into the response stream which will effectively open it on the client machine:
public ActionResult ShowPdf()
{
byte[] fileToShow = FetchPdfFile();
return File(fileToShow, "application/pdf", "report.pdf");
}
And now navigate to /somecontroller/showPdf. If you want the PDF opening inside the browser instead of showing the download dialog you may try adding the following to the controller action before returning:
Response.AddHeader("Content-Disposition", "attachment; filename=report.pdf");
i suggest you use ASP.NET MVC FileResult Class to display the PDF.
see http://msdn.microsoft.com/en-us/library/system.web.mvc.fileresult.aspx
your code open`s the PDF on the webserver.
Here's how I did it.
public ActionResult PrintPDF(byte[] FileToShow, String TempFileName, String Extension)
{
String ReportPath = Path.GetTempFileName() + '.' + Extension;
BinaryWriter bwriter = new BinaryWriter(System.IO.File.Open(ReportPath, FileMode.Create));
bwriter.Write(FileToShow);
bwriter.Close();
return base.File(FileToShow, "application/pdf");
}
Thank you all for your efforts. Solution I used is the most similar to the Darin's one (almost the same, but his is prettier :D), so I will accept his solution.
Vote up for all of you folks (both for answers and comments)
Thanks

Resources